Compara carrozas en php


Answers

Lea primero la advertencia roja http://www.php.net/manual/en/language.types.float.php . Nunca debe comparar carrozas por igualdad. Deberías usar la técnica épsilon.

Por ejemplo:

if (abs($a-$b) < EPSILON) { … }

donde EPSILON es constante y representa un número muy pequeño (debe definirlo)

Question

Quiero comparar dos carrozas en PHP, como en este código de ejemplo:

$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, devuelve el resultado de la condición else lugar de la condición if , aunque $a y $b son iguales. ¿Hay alguna forma especial de manejar / comparar carrozas en PHP?

Si es así, por favor ayúdame a resolver este problema.

¿O hay un problema con la configuración de mi servidor?




Si tiene valores de coma flotante para comparar con la igualdad, una forma simple de evitar el riesgo de la estrategia de redondeo interno del sistema operativo, el lenguaje, el procesador, etc., es comparar la representación de cadena de los valores, como:

if (''. $ a === ''. $ b) {...}

De esta manera, puede ver la igualdad, y la respuesta de PHP será igual a sus deseos. Si es igual para usted cuando lee los valores , la afirmación será verdadera, como se esperaba




function compareFloats($a, $b){
    list($a_int, $a_dec) = explode('.', strval($a));
    list($b_int, $b_dec) = explode('.', strval($b));

    if(intval($a_int) == intval($b_int) && intval($a_dec) == intval($b_dec)){
        return 'same';
    }else{
        if((intval($a_int) < intval($b_int)) || (intval($a_int) === intval($b_int) && intval($a_dec) < intval($b_dec))){
            return 'smaller';
        }
        if((intval($a_int) > intval($b_int)) || (intval($a_int) === intval($b_int) && intval($a_dec) > intval($b_dec))){
            return 'bigger';
        }
        return 'error';
    }
}



Si lo escribe así, probablemente funcione, así que imagino que lo ha simplificado para la pregunta. (Y mantener la pregunta simple y conciso 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 cardinal de programación de coma flotante: nunca hacer 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:

if abs(a - y) < epsilon


1. Uno de los principales problemas es la forma en que escribimos los 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 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 en la expansión binaria y decimal de la fracción. Entonces, 1.25 es exacto porque es 5 / (2 2 * 5 0 ) pero 0.1 no es porque es 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.




Como se dijo antes, tenga mucho cuidado al hacer comparaciones de coma flotante (ya sea igual, mayor, o menor que) en PHP. Sin embargo, si solo está interesado en algunos dígitos significativos, puede hacer algo como:

$a = round(0.17, 2);
$b = round(1 - 0.83, 2); //0.17
if($a == $b ){
    echo 'a and b are same';
}
else {
    echo 'a and b are not same';
}

El uso del redondeo a 2 decimales (o 3, o 4) causará el resultado esperado.




//You can compare if less or more.

$parcela='250.23'; //total value
$tax = (double) '15.23'; //tax value
$taxaPercent=round((100*$tax)/$parcela,2); //tax percent 

$min=(double) '2.50';// minimum tax percent                             

if($taxaPercent < $min ){
    // tax error tax is less than 2.5
}



Si tiene un número pequeño y finito de puntos decimales que serán aceptables, lo siguiente funciona bien (aunque con un rendimiento más lento que la solución épsilon):

$a = 0.17;
$b = 1 - 0.83; //0.17

if (number_format($a, 3) == number_format($b, 3)) {
    echo 'a and b are same';
} else {
    echo 'a and b are not same';
}



if( 0.1 + 0.2 == 0.3 ){
 echo 'a and b are same';
}
else {
 echo 'a and b are not same';
}

Esto causará problems debido a la aritmética de coma flotante estándar IEEE (que tiene este problema).




Para php 7.2 puede trabajar con PHP_FLOAT_EPSILON ( PHP_FLOAT_EPSILON ):

if(abs($a-$b) < PHP_FLOAT_EPSILON){
   echo 'a and b are same';
}