Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is sin(180) not zero when using python and numpy?

Does anyone know why the below doesn't equal 0?

import numpy as np
np.sin(np.radians(180))

or:

np.sin(np.pi)

When I enter it into python it gives me 1.22e-16.

like image 853
MCF Avatar asked Sep 05 '13 21:09

MCF


People also ask

Why is sin pi not zero in Python?

Floating point rounding error. Pi cannot be represented exactly as a floating point number, so sin(pi) isn't going to be exactly zero. Is there a fix or do I need to convert it to int? @ViktorKerkez: You should post that as an answer.

Is Numpy sin in degrees?

The np. sin() NumPy function help to find sine value of the angle in degree and radian.

Is it possible to work with trigonometric operations using Numpy?

Trigonometric Functions. NumPy has standard trigonometric functions which return trigonometric ratios for a given angle in radians. arcsin, arcos, and arctan functions return the trigonometric inverse of sin, cos, and tan of the given angle. The result of these functions can be verified by numpy.


3 Answers

The number π cannot be represented exactly as a floating-point number. So, np.radians(180) doesn't give you π, it gives you 3.1415926535897931.

And sin(3.1415926535897931) is in fact something like 1.22e-16.

So, how do you deal with this?

You have to work out, or at least guess at, appropriate absolute and/or relative error bounds, and then instead of x == y, you write:

abs(y - x) < abs_bounds and abs(y-x) < rel_bounds * y 

(This also means that you have to organize your computation so that the relative error is larger relative to y than to x. In your case, because y is the constant 0, that's trivial—just do it backward.)

Numpy provides a function that does this for you across a whole array, allclose:

np.allclose(x, y, rel_bounds, abs_bounds) 

(This actually checks abs(y - x) < abs_ bounds + rel_bounds * y), but that's almost always sufficient, and you can easily reorganize your code when it's not.)

In your case:

np.allclose(0, np.sin(np.radians(180)), rel_bounds, abs_bounds) 

So, how do you know what the right bounds are? There's no way to teach you enough error analysis in an SO answer. Propagation of uncertainty at Wikipedia gives a high-level overview. If you really have no clue, you can use the defaults, which are 1e-5 relative and 1e-8 absolute.

like image 191
abarnert Avatar answered Sep 20 '22 18:09

abarnert


One solution is to switch to sympy when calculating sin's and cos's, then to switch back to numpy using sp.N(...) function:

>>> # Numpy not exactly zero
>>> import numpy as np
>>> value = np.cos(np.pi/2)
6.123233995736766e-17

# Sympy workaround
>>> import sympy as sp
>>> def scos(x): return sp.N(sp.cos(x))
>>> def ssin(x): return sp.N(sp.sin(x))

>>> value = scos(sp.pi/2)
0

just remember to use sp.pi instead of sp.np when using scos and ssin functions.

like image 30
pico Avatar answered Sep 18 '22 18:09

pico


Faced same problem,

import numpy as np

print(np.cos(math.radians(90)))

>> 6.123233995736766e-17

and tried this,

print(np.around(np.cos(math.radians(90)), decimals=5))

>> 0

Worked in my case. I set decimal 5 not lose too many information. As you can think of round function get rid of after 5 digit values.

like image 31
Meric Ozcan Avatar answered Sep 18 '22 18:09

Meric Ozcan