-
Notifications
You must be signed in to change notification settings - Fork 86
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
Improve accuracy for atan2(y,x) with near-zero x #18
Comments
Hi @grimaldini, since fixed-point math uses integers under the hood, off-by-one errors in the raw values are to be expected depending on how certain operations are performed. You must be mindful of loss of information.
Note that the approximation of 355/133 is actually worse: I'm not sure what you mean by "cos->sin reducing x to a value of two", but any off-by-one errors there are hardly suprising considering it's fixed-point math. In conclusion, it seems everything's working as it should. Please let me know if this answers your question. |
that makes sense but these trigonometric functions don't seem to be able to handle such low results, for example:
|
Allright, that's a fair point. Apparently, |
So after a quick check, I do think this is also a known consequence of using fixed-point math. It might be possible to have an implementation of @grimaldini can you work around your problem by converting to a different fixed-point format before doing |
I'm currently using 32.32 format though, so I do have more bits in the integer part. Do you mean that the integer part needs to be larger than the fractional part, if so why is that the case? is this a problem that might happen with other trig functions, does checking that all the trig functions of (0 + epsilon) can guarantee that a similar issue won't occur? |
Yes, indeed. At least, if you want Example: when dividing 1 (the smallest non-zero integer) by 1*2^-N (the smallest non-zero fraction in a number with N fraction bits), the result is 2^N. This doesn't fit in an N-bit integer. So a quick workaround is having more integer bits than fraction bits. Fixed-point math is not quite a drop-in replacement, since you have to care about the domain and range of functions. That said, |
Are you saying that for a number with N fraction bits, the integer part needs to be at least N+1? Separately, I tried to use Q17.15 but now I am getting other errors such as
How can fixed point arithmetics be reliably used in a complex system such as a physics simulation? where I cannot |
That depends on what inputs you want to have work. If you want division by very small (near-zero) numbers to work, then yes, at least N+1. Likely more.
Fixed-point numbers are deterministic, which is their benefit. But this comes at the cost of having to care about underflow and overflow. You can't just pick a type and work with it as if It were a float. It is fundamental property of fixed point that you have to care about the range of operations. You may have to convert between different fixed-point types during a calculation. |
`atan2(y,x)` requires a lot of bits in the integer part when `x` is near-zero. This is because `atan2(y,x)` does `atan(y/x)` internally and `y/x` easily overflows for very small `x` unless you have more integer bits than fraction bits. However, `atan(q)` does `1/q` if `q > 1`, thereby inverting the original division in `atan2`. So this overflow can be avoided if these divisions are shortcut. Closes #18
`atan2(y,x)` requires a lot of bits in the integer part when `x` is near-zero. This is because `atan2(y,x)` does `atan(y/x)` internally and `y/x` easily overflows for very small `x` unless you have more integer bits than fraction bits. However, `atan(q)` does `1/q` if `q > 1`, thereby inverting the original division in `atan2`. So this overflow can be avoided if these divisions are shortcut. Closes #18
Thanks for the fix! do you think this near-zero input issue might be something affecting other trigonometric functions? |
This particular improvement also affected |
Hi,
I have the following setup:
Could this be caused by this:
static constexpr fixed pi() { return from_fixed_point<61>(7244019458077122842ll); }
I tried changing this to calculate
fixed(355)/fixed(113)
(approximation of pi) and use this instead and it seems to fix the issue but could the from_fixed_point function not be correctly converting between fixed point types?Thanks,
Luis
The text was updated successfully, but these errors were encountered: