-
Notifications
You must be signed in to change notification settings - Fork 21
Fix fixed-point conversion precision to avoid overflow #110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
} | ||
} | ||
|
||
return (twin_angle_t) (double) angle / (32768.0) * TWIN_ANGLE_360; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this commit also aim to fix the incorrect casting of the variable angle
from twin_angle_t
to double
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this commit also aim to fix the incorrect casting of the variable
angle
fromtwin_angle_t
todouble
?
Yes, intentionally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then, why didn't you write this purpose on this commit log ?
src/trig.c
Outdated
|
||
return (twin_angle_t) (double) angle / (32768.0) * TWIN_ANGLE_360; | ||
/* Fixed-point conversion: angle * TWIN_ANGLE_360 / 32768 */ | ||
return (twin_angle_t) ((angle * TWIN_ANGLE_360) >> 15); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since TWIN_ANGLE_360=4096 = 2^12
by simple simplification, the original expression can be represented as
which is equivalent to
+/* Fixed-point conversion: angle * TWIN_ANGLE_360 / 32768 */
+ return (twin_angle_t) (angle >> 3);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the value range of angle
is
(angle * TWIN_ANGLE_360) >> 15
with TWIN_ANGLE_360 = 4096
can cause overflow. The maximum possible result of the multiplication is:
This value exceeds the limits of 16-bit, it may result in integer overflow and unpredictable behavior.
To avoid this issue, the multiplication and division can be replaced with a simple bit shift:
angle >> 3
a0e12f2
to
323e6ad
Compare
The previous implementation used ((angle * TWIN_ANGLE_360) >> 15) which caused integer overflow when angle values reached their maximum range of [-9092, 9092]. The multiplication 9092 * 4096 results in 37,240,832, exceeding the 16-bit signed integer limit. This commit simplifies the expression by factoring out the constants: - Original: angle * TWIN_ANGLE_360 / 32768 - Since TWIN_ANGLE_360 = 2^12 and 32768 = 2^15 - Simplified: angle * 2^12 / 2^15 = angle / 8 Use integer division (not right shift) to match original truncate-towards-zero behavior for negative values. Right shift would round towards negative infinity, causing precision errors for ~87.5% of negative angle values (all non-multiples of 8). Benefits: 1. Eliminates integer overflow risk 2. Avoids incorrect double-precision cast 3. Removes floating-point operations 4. Preserves exact precision for all angle values Addresses review comments from @jouae and @weihsinyeh in PR #110. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
eedd33f
to
a0fde3f
Compare
The previous implementation used ((angle * TWIN_ANGLE_360) >> 15) which caused two critical issues: 1. Integer Overflow: The multiplication 9092 * 4096 results in 37,240,832, exceeding the 16-bit signed integer limit (32,767). It occurs when CORDIC iteration reaches maximum angle accumulation. 2. Precision Error for Negative Values: Right shift (>>) rounds towards negative infinity (floor division), while the original floating-point cast truncates towards zero. This causes precision errors for ~87.5% of negative angle values (all non-multiples of 8). Examples: - Original: (int)(-7 / 32768.0 * 4096) = 0 - Right shift: -7 >> 3 = -1 (WRONG) - Integer division: -7 / 8 = 0 (CORRECT) This commit simplifies the expression by factoring out constants: - Original: angle * TWIN_ANGLE_360 / 32768 - Since TWIN_ANGLE_360 = 2^12 and 32768 = 2^15 - Simplified: angle * 2^12 / 2^15 = angle / 8 This uses integer division (/) instead of right shift (>>) to match the original truncate-towards-zero behavior guaranteed by C99, preserving exact precision for all angle values in CORDIC's [-9092, 9092] range.
a0fde3f
to
439545f
Compare
The commit previous implementation used
((angle * TWIN_ANGLE_360) >> 15)
whichcaused two critical issues:
The multiplication
9092 * 4096
results in 37,240,832, exceeding the16-bit signed integer limit (32,767). It occurs when CORDIC iteration
reaches maximum angle accumulation.
Right shift (>>) rounds towards negative infinity (floor division),
while the original floating-point cast truncates towards zero.
This causes precision errors for ~87.5% of negative angle values
(all non-multiples of 8).
Examples:
This commit simplifies the expression by factoring out constants:
This uses integer division (/) instead of right shift (>>) to match the
original truncate-towards-zero behavior guaranteed by C99, preserving
exact precision for all angle values in CORDIC's [-9092, 9092] range.