Search code examples
pythonnumpyfloating-pointfloating-accuracy

Mitigating Floating Point Approximation Issues with Numpy


My code is quite simple, and only 1 line is causing an issue:

np.tan(np.radians(rotation))

Instead of my expected output for rotation = 45 as 1, I get 0.9999999999999999. I understand that 0 and a ton of 9's is 1. In my use case, however, it seems like the type of thing that will definitely build up over iterations.

What is causing the floating point error: np.tan or np.radians, and how do I get the problem function to come out correctly regardless of floating point inaccuracies?

Edit:

I should clarify that I am familiar with floating point inaccuracies. My concern is that as that number gets multiplied, added, and compared, the 1e-6 error suddenly becomes a tangible issue. I've normally been able to safely ignore floating point issues, but now I am far more concerned about the build up of error. I would like to reduce the possibility of such an error.

Edit 2:

My current solution is to just round to 8 decimal places because that's most likely enough. It's sort of a temporary solution because I'd much prefer a way to get around the IEEE decimal representations.


Solution

  • What is causing the floating point error: np.tan or np.radians, and how do I get the problem function to come out correctly regardless of floating point inaccuracies?

    Both functions incur rounding error, since in neither case is the exact result representable in floating point.

    My current solution is to just round to 8 decimal places because that's most likely enough. It's sort of a temporary solution because I'd much prefer a way to get around the IEEE decimal representations.

    The problem has nothing to do with decimal representation, and this will give worse results outside of the exact case you mention above, e.g.

    >>> np.tan(np.radians(60))
    1.7320508075688767
    >>> round(np.tan(np.radians(60)), 8)
    1.73205081
    >>> np.sqrt(3) # sqrt is correctly rounded, so this is the closest float to the true result
    1.7320508075688772
    

    If you absolutely need higher accuracy than the 15 decimal digits you would get from code above, then you can use an arbitrary precision library like gmpy2.