Pregunta

Tengo otro problema de cálculo matemático otra vez.

$a = 34.56

$b = 34.55

$ a haga algún cálculo para obtener esta cifra

$ b está haciendo el redondeo 0.05 más cercano para obtener esta cifra

lo que pasa es

$c = $b - $a

supuestamente debería ser -0.01, pero hago eco del $ c es show -0.00988888888888

Intento usar n umber_format ($ c, 2) , pero el resultado es 0.00,

¿cómo puedo asegurarme de que $ a y $ b sean exactamente 2 decimales, no hay un número oculto en la parte posterior?

en mi conocimiento de php number_format solo puede formatear la pantalla, pero el valor no es realmente 2 decimal,

Espero poder obtener ayuda de aquí. Esto realmente me frustró.

¿Fue útil?

Solución

Pruebe sprintf (" ;%. 2f " ;, $ c);

Los números de punto flotante se representan en notación IEEE en función de las potencias de 2, por lo que los números decimales de terminación pueden no ser un número binario de terminación, por eso obtienes los dígitos finales.

Como lo sugiere el codificador de longitud variable, si conoce la precisión que desea y no cambia (por ejemplo, cuando se trata de dinero), sería mejor usar números de puntos fijos, es decir, expresar los números como centavos en lugar de que dolares

$a = 3456;

$b = 3455;

$c = $b - $a;

sprintf ("%.2f", $c/100.0);

De esta manera, no tendrá ningún error de redondeo si realiza muchos cálculos antes de imprimir.

Otros consejos

Utilice round () :

$c = round($b - $a, 2);

Nota: también puede elegir el modo de redondeo según corresponda.

Editar: Ok, no entiendo lo que sprintf () está haciendo y que number_format () no es:

$c = number_format($b - $a, 2);

vs

$c = sprintf("%.2f", $b - $a);

?

Cálculo nativo:

$a = 34.56;
$b = 34.55;
$c = $b - $a; // -0.010000000000005    

Funciona como se esperaba (! use siempre las funciones de BC para los cálculos de números reales, el problema es para todas las plataformas basadas en C):

$a = '34.56';
$b = '34.55';
$c = bcsub($b, $a, 4); // -0.0100    

También me encontré con este problema recientemente al hacer cálculos con flotadores. Por ejemplo, tenía 2 flotadores que cuando se restaban y formateaban, el valor era -0.00.

$floatOne = 267.58;
$floatTwo = 267.58;
$result = number_format($floatOne - floatTwo, 2);
print $result; //printed a string -0.00

Lo que hice fue:

$result = abs($floatOne - $floatTwo);// Made the number positive
print money_format('%i', $result); // printed the desired precision 0.00

En mi solución, sé que floatOne nunca será menor que floatTwo. La función money_format solo se define si el sistema tiene capacidades strfmon, Windows no.

Te has encontrado con una de las trampas de los números de punto flotante; que no siempre pueden representar fracciones decimales exactas. Si desea valores decimales exactos, es mejor usar números enteros y luego dividir por la precisión que desea al final.

Por ejemplo, si está haciendo cálculos en flotadores que representan Dólares (o su moneda favorita), es posible que desee realizar sus cálculos en centavos enteros.

Puedes evitar muy bien todos estos problemas simplemente usando la biblioteca bcmath.

Solo recuerde leer la documentación y tenga cuidado si está pasando argumentos como cadenas o tipos de datos numéricos.

Si todavía alguien llega a esta página con problemas similares en los que la resta de números flotantes provoca errores o valores extraños. Quiero explicar este problema con un poco más de detalles. El culpable son los números de punto flotante. Y diferentes sistemas operativos y diferentes versiones de lenguajes de programación pueden comportarse de manera diferente.

Para ilustrar el problema, explicaré por qué con un simple ejemplo a continuación.

No está directamente relacionado con PHP y no es un error. Sin embargo, cada programador debe ser consciente de este problema.

Este problema incluso cobró muchas vidas hace dos décadas.

El 25 de febrero de 1991, este problema en el cálculo del número flotante en una batería de misiles MIM-104 Patriot impidió que interceptara un misil Scud entrante en Dhahran, Arabia Saudita, lo que contribuyó a la muerte de 28 soldados del Destacamento del 14º Intendente del Ejército de los Estados Unidos.

¿Pero por qué sucede?

La razón es que los valores de punto flotante representan una precisión limitada. Por lo tanto, un valor podría No tiene la misma representación de cadena después de cualquier procesamiento. También Incluye la escritura de un valor de punto flotante en su script y directamente imprimiéndolo sin ninguna operación matemática.

Solo un ejemplo simple:

$a = '36';
$b = '-35.99';
echo ($a + $b);

Esperas que se imprima 0.01, ¿verdad? Pero imprimirá una respuesta muy extraña como 0.009999999999998

Al igual que otros números, los números de punto flotante doble o flotante se almacenan en la memoria como una cadena de 0 y 1. La diferencia entre el punto flotante y el entero es la forma en que interpretamos los 0 y los 1 cuando queremos verlos. Hay muchas normas sobre cómo se almacenan.

Los números de punto flotante se suelen empaquetar en un dato de computadora como el bit de signo, el campo exponente y el significando o la mantisa, de izquierda a derecha ...

Los números decimales no están bien representados en binario debido a la falta de espacio suficiente. Entonces, no puedes expresar 1/3 exactamente como es 0.3333333 ..., ¿verdad? Por qué no podemos representar 0.01 como un número binario es por la misma razón. 1/100 es 0.00000010100011110101110000 ..... con una repetición de 10100011110101110000.

Si 0.01 se mantiene en formato simplificado y truncado por el sistema de 01000111101011100001010 en binario, cuando se traduce de nuevo al decimal, se leerá como 0.0099999 ... dependiendo del sistema (las computadoras de 64 bits le darán una precisión mucho mayor que 32 bits). En este caso, el sistema operativo decide si imprimirlo como se ve o cómo hacerlo de una manera más legible. Por lo tanto, depende de la máquina cómo quieren representarlo. Pero puede ser protegido en el nivel de lenguaje con diferentes métodos.

Si formatea el resultado, echo number_format (0.009999999999998, 2); se imprimirá 0.01.

Se debe a que en este caso, usted indica cómo debe leerse y la precisión que necesita.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top