¿Por qué el pecado (180) no es cero cuando se usa python y numpy?

¿Alguien sabe por qué lo de abajo no es igual a 0?

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

o:

 np.sin(np.pi) 

Cuando entro en python me da 1.22e-16.

El número π no se puede representar exactamente como un número de punto flotante. Entonces, np.radians(180) no te da π , te da 3.1415926535897931 .

Y el sin(3.1415926535897931) es en realidad algo así como 1.22e-16 .

Entonces, ¿cómo lidiar con esto?

Tienes que calcular, o al menos adivinar, los límites de error relativos y absolutos apropiados, y luego, en lugar de x == y , escribes:

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

(Esto también significa que tiene que organizar su cálculo para que el error relativo sea mayor en relación con y que con x . En su caso, porque y es la constante 0 , eso es trivial, solo hágalo al revés).

Numpy proporciona una función que lo hace por ti en toda una matriz, todo allclose :

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

(Esto realmente verifica abs(y - x) < abs_ bounds + rel_bounds * y) , pero eso es casi siempre suficiente, y puedes reorganizar fácilmente tu código cuando no lo es.)

En tu caso:

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

Entonces, ¿cómo sabes cuáles son los límites correctos? No hay manera de enseñarle suficiente análisis de errores en una respuesta SO. La propagación de la incertidumbre en Wikipedia ofrece una visión general de alto nivel. Si realmente no tiene una pista, puede usar los valores predeterminados, que son 1e-5 relativos y 1e-8 absolutos.

El problema no es un error de redondeo de pi. Tenga en cuenta que el problema no aparece para el coseno:

  In [2]: np.sin(np.pi) Out[2]: 1.2246467991473532e-16 != 0. In [3]: np.cos(np.pi) Out[3]: -1.0 == -1. 

El problema es mucho más … complicado. Está relacionado con la precisión de pi dentro del procesador. Esto fue descubierto y explicado aquí: https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/