Skip to content

Commit 439545f

Browse files
committed
Fix conversion precision to avoid overflow
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.
1 parent 2e75289 commit 439545f

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

src/trig.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,15 @@ static twin_angle_t twin_atan2_first_quadrant(twin_fixed_t y, twin_fixed_t x)
148148
}
149149
}
150150

151-
return (twin_angle_t) (double) angle / (32768.0) * TWIN_ANGLE_360;
151+
/* Fixed-point conversion: angle / 32768 * TWIN_ANGLE_360
152+
* Simplified: angle * 2^12 / 2^15 = angle / 8
153+
* Use integer division (not right shift) to match original
154+
* truncate-towards-zero behavior for negative values. Right shift would
155+
* round towards negative infinity, causing precision errors for
156+
* non-multiples of 8. Avoids overflow since no intermediate multiplication
157+
* required.
158+
*/
159+
return (twin_angle_t) (angle / 8);
152160
}
153161

154162
twin_angle_t twin_atan2(twin_fixed_t y, twin_fixed_t x)

0 commit comments

Comments
 (0)