2009-10-22 20 views
13

Ha vuelto a tener otro problema de cálculo matemático.cálculo de flotador php 2 punto decimal

$a = 34.56 

$b = 34.55 

$a hacer algunos cálculos para obtener esta cifra

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

lo que sucede es

$c = $b - $a 

supuestamente debería estar -0.01, pero echo de menos el $c se muestra -0.00988888888888

intento utilizar n umber_format($c, 2), pero la salida es 0,00,

cómo puedo hacer para asegurar $a$b y es exactamente 2 decimales, sin número oculto en la parte trasera.

en mi php conocimiento Number_format sólo es capaz de dar formato a la pantalla, pero el valor no es realmente 2 decimales,

espero que pueda obtener ayuda de aquí. Esto realmente me frustró.

+0

Investigue 'precision' en php.ini para ver cambios más amplios en todo PHP. Sin embargo, tenga en cuenta que está tratando con * dígitos significativos * allí. –

Respuesta

34

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

números de punto flotante IEEE están representados en notación basado en las potencias de 2, por lo que terminan números decimales pueden no ser un número binario que termina, por eso se obtiene los dígitos de cola.

Según lo sugerido por el codificador de longitud variable, si conoce la precisión que desea y no cambia (por ejemplo, cuando se trata de dinero) podría ser mejor usar números de punto fijo, es decir, expresar los números como centavos en lugar de dólares

$a = 3456; 

$b = 3455; 

$c = $b - $a; 

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

de esta manera, usted no tendrá ningún errores de redondeo si lo hace un montón de cálculos antes de imprimir.

+0

gracias por su respuesta, la única forma es formatear la salida, no es posible configurarla en 2 decimales, excepto con String. – Shiro

+0

Si solo desea establecerlo en 2 decimales, debe usar números de punto fijo, no coma flotante. Vea la respuesta del codificador de longitud variable. –

+0

Realmente no entiendo lo que significa con números de "punto fijo", ¿pueden darnos algún ejemplo? ¡Muchas gracias! – Shiro

12

Uso round():

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

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

Editar: autorización I no consiguen lo que está haciendo sprintf()number_format() no es:

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

vs

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

?

+0

Probablemente nada, pero sprintf() es mucho más divertido de usar para tipos como yo que están acostumbrados a C. También guarda una escritura '$ foo = number_format ($ b - $ a, 2). "manzanas!" 'y en su lugar escribir' $ foo = sprintf ("%. 2f manzanas!", $ b - $ a) '- mucho más elegante, en mi opinión. –

+0

Rocas redondas, tal vez porque eso es todo lo que sé por el momento, todavía estoy aprendiendo. – Newb

2

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

Por ejemplo, si está haciendo cálculos en flotantes que representan dólares (o su moneda favorita), puede hacer sus cálculos en centavos enteros.

+0

¿podría por favor dar un ejemplo de cómo funcionan los centavos enteros? Realmente no entiendes lo que quieres decir. Muchas gracias por tu comentario. – Shiro

+0

"Centavos enteros" significa que, por ejemplo, la cantidad de $ 24.95 debe almacenarse no como un punto flotante 24.95, sino como el número entero 2495. El monto $ 10.00 se almacenará como el entero 1000. Y así sucesivamente. –

2

Puede esquivar muy bien todos estos problemas simplemente utilizando la biblioteca bcmath.

Simplemente recuerde leer la documentación y tenga cuidado ya sea que esté pasando argumentos como cadenas o como tipos de datos numéricos.

4

Cálculo Nativo:

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

funciona como se espera (utilizar siempre funciona BC para cálculos con números reales, el problema es que todas las plataformas basadas en C!):

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

Para seguir iterando sobre esto. Use cadenas para representar los datos en lugar de los tipos de datos flotantes/dobles. Luego use las funciones de BCMath para calcular las variables. Para utilizar sprintf ('% 1 $ s', bcadd ($ var1, $ var2)); Lo mismo se aplica al almacenamiento de datos de bases de datos. http://php.net/manual/en/book.bc.php – fyrye

3

I también se encontró con este problema recientemente al hacer cálculos con flotadores. Por ejemplo, tuve 2 flotantes que cuando se restaron y formatearon, el valor fue -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á inferior a floatTwo. La función money_format solo está definida si el sistema tiene capacidades de strfmon, Windows no.

1

Si todavía alguien llega a esta página con problemas similares donde la resta de números flotante causa valores extraños o erróneos. Quiero explicar este problema con un poco más de detalles. El culpable es el número de coma 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 tener en cuenta este problema.

Este problema incluso costó muchas vidas hace dos décadas. El 25 de febrero de 1991, este problema en el cálculo de números flotantes en una batería de misiles Patriot MIM-104 impidió que interceptara un misil Scud entrante en Dhahran, Arabia Saudita, contribuyendo a la muerte de 28 soldados del Destacamento de Cuarteles del 14to. Ejército de los EE. UU.

¿Pero por qué sucede?

La razón es que los valores de coma flotante representan una precisión limitada. Por lo tanto, un valor podría no tener la misma representación de cadena después de cualquier procesamiento. También incluye escribir un valor de punto flotante en su secuencia de comandos y directamente imprimirlo sin ninguna operación matemática.

Sólo un ejemplo sencillo:

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

era de esperar, para imprimir 0,01, ¿verdad? Pero imprimirá una respuesta muy extraña como 0.009999999999998

Al igual que otros números, los números de coma flotante dobles o flotantes se almacenan en la memoria como una cadena de 0 y 1.La forma en que el punto flotante difiere del número entero es en la forma en que interpretamos los 0 y los 1 cuando queremos verlos. Hay muchos estándares de cómo se almacenan.

números de coma flotante se empaquetan en general un dato equipo que el bit de signo, el campo exponente y la mantisa o 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 exactamente 1/3 ya que es 0.3333333 ... ¿verdad? Por qué no podemos representar 0.01 como un número flotante binario es por la misma razón. 1/100 es 0.00000010100011110101110000 ..... con una repetición de 10100011110101110000.

Si 0,01 se mantiene en forma simplificada y truncado sistema de 01000111101011100001010 en binario, cuando se traduce de nuevo a decimal, sería leído como 0,0099999. ... dependiendo del sistema (las computadoras de 64 bits le darán una precisión mucho mejor que las de 32 bits). El sistema operativo decide en este caso si imprimirlo como lo ve o cómo hacerlo de una manera más legible para el ser humano. Entonces, depende de la máquina cómo quieren representarlo. Pero puede protegerse en el nivel de idioma con diferentes métodos.

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

Esto se debe a que en este caso debe indicar cómo debe leerse y qué precisión necesita.

Cuestiones relacionadas