Skip to content

Conversation

jserv
Copy link
Contributor

@jserv jserv commented Jul 30, 2025

The commit 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.

}
}

return (twin_angle_t) (double) angle / (32768.0) * TWIN_ANGLE_360;
Copy link
Collaborator

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?

Copy link
Contributor Author

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?

Yes, intentionally.

Copy link
Collaborator

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);
Copy link
Collaborator

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^12by simple simplification, the original expression can be represented as

$$\frac{\text{angle} * 4096}{32768} = \text{angle} * 2^{12} *2^{-15} = \text{angle} * 2^{-3}$$

which is equivalent to

+/* Fixed-point conversion: angle * TWIN_ANGLE_360 / 32768 */
+    return (twin_angle_t) (angle >> 3);

Copy link
Collaborator

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 $[-9092,9092]$, using the original expression:

(angle * TWIN_ANGLE_360) >> 15

with TWIN_ANGLE_360 = 4096 can cause overflow. The maximum possible result of the multiplication is:

$$9092 * 4096 = 37,249,024$$

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

@sysprog21 sysprog21 deleted a comment from cubic-dev-ai bot Oct 16, 2025
@sysprog21 sysprog21 deleted a comment from cubic-dev-ai bot Oct 16, 2025
cubic-dev-ai[bot]

This comment was marked as outdated.

@jserv jserv force-pushed the fixedpoint-atan2 branch 3 times, most recently from a0e12f2 to 323e6ad Compare October 16, 2025 10:04
jserv added a commit that referenced this pull request Oct 16, 2025
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]>
@jserv jserv force-pushed the fixedpoint-atan2 branch 2 times, most recently from eedd33f to a0fde3f Compare October 16, 2025 10:08
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.
@jserv jserv changed the title Replace FP division with fixed-point shift in atan2 Fix fixed-point conversion precision to avoid overflow Oct 16, 2025
cubic-dev-ai[bot]

This comment was marked as outdated.

@jserv jserv requested review from jouae and weihsinyeh October 16, 2025 10:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants