user8866053
user8866053

Reputation:

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.

Upvotes: 1

Views: 1897

Answers (2)

Simon Byrne
Simon Byrne

Reputation: 7874

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.

Upvotes: 1

Tarifazo
Tarifazo

Reputation: 4343

Take a look here: https://docs.scipy.org/doc/numpy/user/basics.types.html .

Standard dtypes in numpy do not go beyond 64 bits precision. From the docs:

Be warned that even if np.longdouble offers more precision than python float, it is easy to lose that extra precision, since python often forces values to pass through float. For example, the % formatting operator requires its arguments to be converted to standard python types, and it is therefore impossible to preserve extended precision even if many decimal places are requested. It can be useful to test your code with the value 1 + np.finfo(np.longdouble).eps.

You can increase precision with np.longdouble, but this is platform dependent

In spyder (windows):

np.finfo(np.longdouble).eps  #same precision as float
>> 2.220446049250313e-16
np.finfo(np.longdouble).precision
>> 15

In google colab:

np.finfo(np.longdouble).eps  #larger precision
>> 1.084202172485504434e-19
np.finfo(np.longdouble).precision
>> 18

print(np.tan(np.radians(45, dtype=np.float), dtype=np.float) - 1)
print(np.tan(np.radians(45, dtype=np.longfloat), dtype=np.longfloat) - 1)
>> -1.1102230246251565e-16
0.0

Upvotes: 0

Related Questions