Quiero comparar dos flotantes en PHP, como en este código de muestra:
$a = 0.17;
$b = 1 - 0.83; //0.17
if($a == $b ){
echo 'a and b are same';
}
else {
echo 'a and b are not same';
}
En este código se devuelve el resultado de la else
condición en lugar de la if
condición, a pesar de que $a
y $b
son iguales. ¿Hay alguna forma especial de manejar / comparar flotantes en PHP?
En caso afirmativo, ayúdame a resolver este problema.
¿O hay un problema con la configuración de mi servidor?
php
floating-point
Santosh Sonarikar
fuente
fuente
a and b are same
. ¿Es este tu código completo?floating-point
descripción de la etiqueta? stackoverflow.com/tags/floating-point/info Ese es un comportamiento que probablemente encontrarás en cualquier lenguaje de programación, cuando uses números de punto flotante. Ver, por ejemplo, stackoverflow.com/questions/588004/is-javascripts-math-brokenRespuestas:
Si lo haces así, deberían ser lo mismo. Pero tenga en cuenta que una característica de los valores de coma flotante es que los cálculos que parecen dar como resultado el mismo valor no necesitan ser idénticos. Entonces, si
$a
es un literal.17
y$b
llega allí a través de un cálculo, bien puede ser que sean diferentes, aunque ambos muestren el mismo valor.Por lo general, nunca compara los valores de coma flotante para una igualdad como esta, necesita usar una diferencia mínima aceptable:
Algo como eso.
fuente
abs($a-$b)
>abs(($a-$b)/$b)
0.10000000000000000555111512312578270211815834045410156
generalmente no tiene sentido y preferirían en su0.1
lugar. Y escribir un número para que pueda leerse de nuevo exactamente de la misma manera. Como puede ver, no es tan claro como parece. Y para que conste, todavía se desea comparar los números de punto flotante, como he mostrado, ya que puede llegar a$a
y$b
a través de diferentes cálculos que se hacen diferentes.a=b=0
y sia
es el valor positivo cero más pequeño posible yb
es el valor negativo distinto de cero más pequeño posible, la prueba fallará incorrectamente. Alguna buena información aquí: floating-point-gui.de/errors/comparison$b
? el manual de PHP acaba de hacerif(abs($a-$b) < $epsilon)
el manual de MySQL también hizo lo mismoHAVING ABS(a - b) <= 0.0001
$a == $b == 0
, pero ya es mucho más general que el error absoluto. Si$a
y$b
se cuentan por millones, entonces suEPSILON
tendrían que ser muy diferente que si$a
y$b
están en algún lugar cerca0
. Enlace de Ver Dom arriba para una mejor discusión de esto.Lea primero la advertencia roja en el manual . Nunca debes comparar las carrozas por la igualdad. Debes usar la técnica epsilon.
Por ejemplo:
donde
PHP_FLOAT_EPSILON
es constante representando un número muy pequeño (debe definirlo en versiones anteriores de PHP anteriores a 7.2)fuente
EPSILON
aquí hay una constante arbitraria definida por el usuario. PHP no tiene una constante incorporada que represente la idea específica de una arquitectura de epsilon. (Véase tambiénget_defined_constants
.)PHP_FLOAT_EPSILON
El número positivo representable más pequeño x, de modo que x + 1.0! = 1.0. Disponible a partir de PHP 7.2.0.echo $a - $b; /* 5.6843418860808E-14 */ echo PHP_FLOAT_EPSILON; /* 2.2204460492503E-16 */
La pregunta es cómo desea definir "igual" para su aplicación, qué tan cerca deben estar los números para ser considerados iguales.O intente usar las funciones matemáticas de bc:
Resultado:
fuente
bccomp()
toma cadenas como argumentos. De todos modos, podría usarPHP_FLOAT_DIG
para el argumento de escala.Como se dijo antes, tenga mucho cuidado al hacer comparaciones de punto flotante (ya sea igual a, mayor que o menor que) en PHP. Sin embargo, si solo está interesado en unos pocos dígitos significativos, puede hacer algo como:
El uso de redondeo a 2 decimales (o 3, o 4) causará el resultado esperado.
fuente
loose_float_compare
para que sea obvio lo que está sucediendo.bccomp($a, $b, 2)
es superior a su solución. En este ejemplo, el 2 es la precisión. puede configurarlo en cualquier número de puntos flotantes que desee comparar.Sería mejor utilizar la comparación nativa de PHP :
fuente
Si tiene valores de coma flotante para comparar con la igualdad, una forma simple de evitar el riesgo de una estrategia de redondeo interno del sistema operativo, lenguaje, procesador, etc., es comparar la representación de cadena de los valores.
Puede usar cualquiera de los siguientes para producir el resultado deseado: https://3v4l.org/rUrEq
Tipo de cuerda de fundición
Concatenación de cuerdas
función strval
Las representaciones de cadenas son mucho menos delicadas que las flotantes cuando se trata de verificar la igualdad.
fuente
(string)
operación de conversión se realiza por referencia, cambiando la declaración original? Si es así, ese no es el caso 3v4l.org/CraasSi tiene un número pequeño y finito de puntos decimales que será aceptable, lo siguiente funciona bien (aunque con un rendimiento más lento que la solución epsilon):
fuente
Esto funciona para mí en PHP 5.3.27.
fuente
Para PHP 7.2, puede trabajar con PHP_FLOAT_EPSILON ( http://php.net/manual/en/reserved.constants.php ):
fuente
==
y!=
pero no>
,>=
,<
,<=
Si lo escribe así, probablemente funcionará, así que imagino que lo ha simplificado para la pregunta. (Y mantener la pregunta simple y concisa es normalmente algo muy bueno).
Pero en este caso me imagino que un resultado es un cálculo y un resultado es una constante.
Esto viola una regla fundamental de la programación de coma flotante: nunca haga comparaciones de igualdad.
Las razones para esto son un poco sutiles 1, pero lo que es importante recordar es que generalmente no funcionan (excepto, irónicamente, para valores integrales) y que la alternativa es una comparación difusa en la línea de:
1. Uno de los principales problemas implica la forma en que escribimos números en los programas. Los escribimos como cadenas decimales y, como resultado, la mayoría de las fracciones que escribimos no tienen representaciones exactas de la máquina. No tienen formas finitas exactas porque se repiten en binario. Cada fracción de 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 2 n para ninguno de ellos. Solo cuando m == 0 hay una representación finita tanto en la expansión binaria como decimal de la fracción. Entonces, 1.25 es exacto porque es 5 / (2 2 * 5 0) pero 0.1 no es porque sea 1 / (2 0 * 5 1 ). De hecho, en la serie 1.01 .. 1.99 solo 3 de los números son exactamente representables: 1.25, 1.50 y 1.75.
fuente
round($float, 3) == round($other, 3)
Aquí está la solución para comparar puntos flotantes o números decimales
Lanza una
decimal
variable astring
y estarás bien.fuente
La comparación de flotadores para igualdad tiene un ingenuo algoritmo O (n).
Debe convertir cada valor flotante en una cadena, luego comparar cada dígito comenzando desde el lado izquierdo de la representación de cadena flotante utilizando operadores de comparación de enteros. PHP emitirá automáticamente el dígito en cada posición de índice a un entero antes de la comparación. El primer dígito más grande que el otro romperá el bucle y declarará el flotante al que pertenece como el mayor de los dos. En promedio, habrá 1/2 * n comparaciones. Para carrozas iguales entre sí, habrá n comparaciones. Este es el peor de los casos para el algoritmo. El mejor de los casos es que el primer dígito de cada flotante sea diferente, causando solo una comparación.
No puede utilizar OPERADORES DE COMPARACIÓN INTEGRALES en valores flotantes sin procesar con la intención de generar resultados útiles. Los resultados de tales operaciones no tienen sentido porque no está comparando enteros. Está violando el dominio de cada operador que genera resultados sin sentido. Esto también es válido para la comparación delta.
Utilice operadores de comparación de enteros para lo que están diseñados: comparar enteros.
SOLUCIÓN SIMPLIFICADA
fuente
2019
TL; DR
Usa mi función a continuación, así
if(cmpFloats($a, '==', $b)) { ... }
cmpFloats($a, '<=', $b)
vsbccomp($a, $b) <= -1
Resumen
Revelaré el misterio.
Entonces, si prueba lo siguiente, será igual:
¿Cómo obtener el valor real del flotador?
¿Cómo puedes comparar?
==
y!=
, puede convertirlos en cadenas, debería funcionar perfectamente:Escriba cast con cadena :
O encasillado con
number_format()
:Advertencia:
Evite soluciones que impliquen manipular flotantes matemáticamente (multiplicar, dividir, etc.) y luego comparar, en su mayoría resolverán algunos problemas e introducirán otros problemas.
Solución sugerida
He creado una función PHP pura (no se necesitan dependencias / bibliotecas / extensiones). Comprueba y compara cada dígito como una cadena. También funciona con números negativos.
fuente
La función de @evilReiko tiene algunos errores como estos:
En mi función, he corregido estos errores, pero de todos modos, en algunos casos, esta función devuelve respuestas incorrectas:
Función fija para comparar flotadores
Responde a tu pregunta
fuente
Aquí hay una clase útil de mi biblioteca personal para tratar con números de coma flotante. Puede modificarlo a su gusto e insertar cualquier solución que desee en los métodos de clase :-).
fuente
Respuesta simple:
fuente