2010-10-12 19 views
6

Si foo es de tipo flotante, ¿la siguiente expresión es válida/recomendada?Comparación de coma flotante 0

(0.0f == foo * float(0)) 

¿Tendrá el valor esperado (matemático) independientemente del valor de foo?

¿El estándar C++ define el comportamiento o es específico de la implementación?

+0

tratar de depurarlo.. – rkellerm

+0

@ rursw1 Más interesado si hay una garantía del estándar – CsTamas

+0

@ rursw1: Eso no va a funcionar. –

Respuesta

2

yo sepa, no caerá necesariamente, también podría terminar muy cerca de 0.

En general, es mejor comparar contra un épsilon. Uso una función como esta para hacer tales comparaciones:

float EpsilonEqual(float a, float b, float epsilon) 
{ 
    return fabsf(a - b) < epsilon; 
} 
+0

@Armen: Tiene toda la razón su fabsf :) – Goz

+1

IEEE 754 indica que -0.0f == + 0.0f, aunque los valores de los bits son diferentes. –

+0

@Michael: suficiente. Sin embargo, eso no quita importancia al punto. Sin embargo, eliminaré la referencia. – Goz

3

Bueno, en primer lugar no es realmente una cuestión de estándar C++. Más bien, lo que está en cuestión es su estándar de modelo de punto flotante (muy probablemente IEEE).

Para flotadores IEEE, probablemente sea seguro, ya que float(0) debería dar como resultado el mismo número que 0.0f, y el multiplicado por cualquier otro número también debería ser 0.0f.

Lo que no es realmente seguro es realizar otras operaciones de coma flotante (p. Ej .: suma y resta con números no enteros) y compararlas con 0.0f.

+6

Al multiplicar cualquier valor IEEE finito por cero, se obtiene cero. Si 'foo' es infinito o NaN, entonces el resultado de la multiplicación es NaN, y el resultado de la comparación es falso. –

+0

@Mike Seymour - Buen punto. Tal vez esa línea estaba destinada a ser un control de que foo es un valor flotante válido. –

1

Con esa declaración en particular, puede estar bastante seguro de que el resultado será 0 y la comparación sea true - No pienso estándar de C++ en realidad lo receta, pero cualquier aplicación razonable de tipos de punto flotante tendrá 0 obra como ese.

Sin embargo, para la mayoría de otros cálculos, el resultado no puede se espera que sea exactamente igual a un literal del resultado matemáticamente correcto:

¿Por qué mis números, como 0,1 + 0,2 complemento hasta una buena ronda 0.3, y en su lugar me sale un resultado extraño como 0.30000000000000004?

Debido internamente, equipos utilizan un formato (binario de coma flotante) que no puede representar con precisión un número como 0,1, 0,2 o 0,3 en absoluto.

Cuando se compila el código o interpretado, su “0.1” es ya redondeado al número más cercano en ese formato , lo que resulta en una pequeña error de redondeo, incluso antes de que ocurra el cálculo .

Leer The Floating-Point Guide explicaciones detalladas y cómo hacerlo correctamente comparisons with expected values.

0

acabo de leer este artículo en MSDN acerca de la opción/fp en VisualStudio link text

optimizaciones de expresión que son válido para valores especiales (NAN, + infinito, -infinity, 0, -0) no será permitido.Las optimizaciones xx => 0, x * 0 => 0, x-0 => x, x + 0 => xy 0-x => -x no son válidos por varios motivos (consulte IEEE 754 y el estándar C99 ).

+0

Supongo que el comentario aquí solo se refiere al hecho de que x * 0 es NaN si x es NaN. – hobbs

2

NaNs e Infinites pueden arruinar tales comparaciones, como otros ya han mencionado.

Sin embargo, hay otra trampa: en C++ no puede confiar en una expresión de tiempo de compilación de tipo flotante, comparando igual a la misma expresión evaluada en tiempo de ejecución.

El motivo es que C++ permite una mayor precisión para los cálculos de fp, de cualquier manera. Ejemplo:

#include <iostream> 

// This provides sufficent obfuscation so that g++ doesn't just inline results. 
bool obfuscatedTrue() { return true; } 

int main() 
{ 
    using namespace std; 

    double const a = (obfuscatedTrue()? 3.0 : 0.3); 
    double const b = (obfuscatedTrue()? 7.0 : 0.7); 
    double const c = a/b; 

    cout << (c == a/b? "OK." : "\"Wrong\" comparision result.") << endl; 
} 

Los resultados con un compilador en particular:

C:\test> g++ --version | find "++" 
g++ (TDM-2 mingw32) 4.4.1 

C:\test> g++ fp_comparision_problem.cpp & a 
"Wrong" comparision result. 

C:\test> g++ -O fp_comparision_problem.cpp & a 
OK. 

C:\test> _ 

Saludos & HTH,

- Alf

+0

¿Con qué precisión mayor teme que el resultado de 'foo * float (0)' pueda ser diferente del resultado de la multiplicación realizada con la precisión del tipo? –

+0

¿Hay alguna utilidad para permitir que los compiladores produzcan resultados distintos a los que se producirían al forzar los operandos de los operadores de comparación a sus tipos de tiempo de compilación (por ejemplo, permitir que 'someFloat == otherFloat/3.0f' se evalúe como si fuera '(double) someFloat == (double) otherFloat/3.0')? Me parece que en la gran mayoría de los casos en que este último es "más rápido", también arrojaría resultados inútiles. – supercat

+0

@PascalCuoq: el asnwer contiene un ejemplo completo, con salida. y entonces la idea de que esto es algo en lo que "temo" que "podría" suceder, parece indicar que no has leído la respuesta. por lo tanto, sugiero que lo hagas. –

Cuestiones relacionadas