2012-03-26 20 views
6

Intento crear casos de prueba unitarios para verificar que los valores de mi tabla sean correctos o incorrectos.problema en la comparación de doble valor con php

Este es mi códigos

echo $a = 2/9; 
echo "<br>".$b=0.22222222222222; 

echo "<br>".gettype($a); 
echo "<br>".gettype($b); 
if($a==$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal"; 


if((string)$a==(string)$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal"; 

Por qué mi primera condición si no funciona? No puedo encontrar el motivo. Por favor, ayúdame.

+2

Posible duplicado de http://stackoverflow.com/questions/3148937/compare-floats-in-php NUNCA compare float con '=='. También '2/9' no es' 0.22222222222222'. La parte decimal continúa infinitamente, por lo que su comparación debería fallar incluso si PHP calculaba flotantes simbólicamente. – Basti

Respuesta

10

La prueba viola una regla fundamental de la programación de punto flotante: nunca se hacen comparaciones de igualdad.

Hay un número de problemas que se derivan del hecho de que las fracciones de punto flotante tienen un número grande pero finito de bits. Estos problemas se denominan comúnmente "errores de redondeo" aunque en su mayor parte no son errores, sino limitaciones de formato.

Por ejemplo, debido a la forma en que escribimos números al programar ... como cadenas de decimales ... la mayoría de los números que podemos escribir no tienen una representación correspondiente en el formato de punto flotante si tienen una fracción decimal. La parte fraccional se repite en la base dos.

Esto descarta en gran medida la comparación exacta de los números de punto flotante, excepto, irónicamente, entre los valores integrales. Es necesario implementar una comparación difusa como abs(a - b) < epsilon.

Y, de hecho, su 2/9 es un caso bote que no tiene una representación finita como ya sea una cadena decimal o una cadena binaria !

Para comparar 2/9 con éxito por la igualdad con una constante de los lugares más requisitos para la perfección en el programa, el intérprete, y la biblioteca que se puede contar.

Por ejemplo, tendría que escribir más 2 s de lo que necesita y el intérprete debería redondear los bits de orden baja de la constante con conocimiento de mayor precisión que el formato. La máquina en realidad tiene algunos conocimientos adicionales al realizar la operación, pero el intérprete puede no hacerlo al convertir la constante. Además, el redondeo en tiempo de ejecución está sujeto a varias opciones y un lenguaje como PHP puede no especificar exactamente cómo las constantes irrepresentables se redondean desde el código fuente a la forma interna.

Y en realidad es peor que eso, porque el individuo 0.2/10 n componentes en la secuencia decimal también no tienen equivalentes binarios exactos. Por lo tanto, es bastante probable que una conversión realmente perfecta y fiel de 0.22222222222222 haga no en realidad igual a una representación de mejor esfuerzo del 2/9 real. No se puede expresar como una cadena decimal finita la fracción exacta de base 2 que más cerca representa 2/9 en cualquier número específico (finito) de bits.

(Debemos tener en alguna parte una respuesta estándar por no hacer comparaciones de igualdad con los números de punto flotante.)


1. Cada fracción máquina es un número racional de la forma x/2 n . Ahora, las constantes son decimales y cada constante decimal es un número racional de la forma x/(2 n * 5 m). Los números de 5 m son impares, por lo que no hay un factor de 0 n para ninguno de ellos. Solo cuando m == 0 hay una representación finita en la expansión binaria y decimal de la fracción. Por ejemplo, 1.25 es exacto porque es 5/(2 * 5) pero 0.1 no es porque es 1/(2 * 5). Y para el número racional 2/9, no hay un 2 no un 5 m factor.

3

Si echa un vistazo a la documentación PHP de floating point numbers (que incluye dobles), verá rápidamente que es increíblemente difícil de comparar debido a la naturaleza de los números flotantes.

Así que nunca confíe en los resultados de números flotantes hasta el último dígito, y no compare los números de punto flotante directamente para la igualdad.

La documentación dar un ejemplo, así:

<?php 

$a = 1.23456789; 
$b = 1.23456780; 
$epsilon = 0.00001; 

if(abs($a-$b) < $epsilon) { 
    echo "true"; 
} 
4

Los flotadores son complicados, debe limitar el número de decimales.

$a = 2/9; 
$b=0.22222222222222; 

$a = number_format($a, 9); 
$b = number_format($b, 9); 

echo "a = " . $a . " and b = " . $b; 

echo "<br>".gettype($a); 
echo "<br>".gettype($b); 
if($a==$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal"; 


if((string)$a==(string)$b){ 
    echo "<br>". "equal"; 
}else echo "<br>". "Not equal";