2011-07-31 20 views
6

Dado que PI/2 nunca se puede representar con precisión en coma flotante, ¿es seguro asumir que cos (a) nunca puede devolver el cero exacto?Puede cos (a) siempre igual a 0 en coma flotante

Si este es el caso, entonces el siguiente pseudo-código nunca entrar en el bloque (y podría ser eliminado con seguridad):

... 
y = h/cos(a); 
if (!isfinite(a)) 
{ 
    // handle infinite y 
} 
+0

ocasiones, el sistema podría forzarlo cero cuando 'a' es aprox. igual a 'pi/2'. – ja72

Respuesta

4

cero es uno de varios valores que se pueden representar exactamente. Muchos sistemas tienen una tabla de búsqueda para los valores comunes de sin y cos, por lo que no es inconcebible que se devuelva exactamente cero.

Pero usted es más seguro usar un delta comparar, antes de realizar la división:

if (Abs(cos(a)) < 0.0000001) 
{ 

} 
+2

¿Uno de "varios"? No creo que use el término "varios" para (2^64 - 2^53). –

+0

1/2, 1/4, 1/8, ..... –

+1

Cada valor de punto flotante finito se puede representar exactamente en coma flotante (impactante, lo sé). No solo 1/2, 1/4, sino también 0.333333333333333314829616256247390992939472198486328125 y 3.141592653589790007373494518105871975421905517578125. –

0

no, esto no puede ser garantizada, porque cos es en sí mismo calcula con un error, por lo que su valor puede ser un cero exacto con bastante facilidad.

7

distinto de cero, el valor de precisión doble que más se acerca a un múltiplo exacto de π/2 es 6381956970095103 * 2^797 , que es igual a:

(an odd integer) * π/2 + 2.983942503748063...e−19 

por lo tanto, para todos los valores de precisión doble x, tenemos el límite:

|cos(x)| >= cos(2.983942503748063...e−19) 

Tenga en cuenta que este es un límite en el valor matemáticamente exacto, no en el valor devuelto por la función de biblioteca cos. En una plataforma con una biblioteca matemática de buena calidad, este límite es lo suficientemente bueno para que podamos decir que cos(x) no es cero para ninguna precisión doble x. De hecho, resulta que esto no es exclusivo del doble; esta propiedad es válida para todos los tipos básicos de IEEE-754, si cos se redondea fielmente.

Sin embargo, eso no quiere decir que esto nunca podría ocurrir en una plataforma que tuvo una implementación espectacularmente pobre de reducción de argumento trigonométrico.

Aún más importante, es fundamental tener en cuenta que en su ejemplo y puede ser infinita sincos(a) siendo cero:

#include <math.h> 
#include <stdio.h> 

int main(int argc, char *argv[]) { 
    double a = 0x1.6ac5b262ca1ffp+849; 
    double h = 0x1.0p1022; 
    printf("cos(a) = %g\n", cos(a)); 
    printf("h/cos(a) = %g\n", h/cos(a)); 
    return 0; 
} 

compilar y ejecutar:

scanon$ clang example.c && ./a.out 
cos(a) = -4.68717e-19 
h/cos(a) = -inf 
+0

Me hubiera gustado responder exactamente esto, y junto a él da pistas sobre por qué una tolerancia como 0.0000001 suena completamente arbitraria, incluso no evitaría un desbordamiento. La protección de desbordamiento debería ser algo así como si (abs (cos (x)) <1);) –

Cuestiones relacionadas