Prueba esto como una solución rápida:
$price_int = intval(floor($price_corrected + 0.5));
El problema que está experimentando no es culpa del PHP, todos los lenguajes de programación utilizando números reales con la aritmética de punto flotante tienen problemas similares.
La regla general para los cálculos monetarios es no utilizar flotantes (ni en la base de datos ni en el script). Puede evitar todo tipo de problemas almacenando siempre los centavos en lugar de dólares. Los centavos son enteros, y puedes agregarlos libremente y multiplicar por otros enteros. Cada vez que muestre el número, asegúrese de insertar un punto delante de los últimos dos dígitos.
La razón por la que está recibiendo 114 en lugar de 115 es que floor
rondas hacia abajo, hacia el número entero más próximo, por lo tanto baja (114.999999999) se convierte en 114. La pregunta más interesante es la razón por 1.15 * 100 es 114.999999999 en lugar de 115. La razón para eso es que 1.15 no es exactamente 115/100, pero es un poco menos, así que si multiplicas por 100, obtienes un número un poco más pequeño que 115.
Aquí hay una explicación más detallada de lo que echo 1.15 * 100;
hace:
- Analiza 1.15 a un número de punto flotante binario. Esto implica redondeo, se redondea un poco para obtener el número binario flotante más cercano a 1.15. La razón por la que no puede obtener un número exacto (sin error de redondeo) es que 1.15 tiene un número infinito de números en la base 2.
- Analiza 100 a un número de punto flotante binario. Esto implica el redondeo, pero como 100 es un entero pequeño, el error de redondeo es cero.
- Calcula el producto de los dos números anteriores. Esto también implica un pequeño redondeo, para encontrar el número de punto flotante binario más cercano. El error de redondeo resulta ser cero en esta operación.
- Convierte el número de punto flotante binario a un número decimal base 10 con un punto, e imprime esta representación. Esto también implica un pequeño redondeo.
La razón por PHP imprime la sorprendente Corrected price = float(115)
(en lugar de 114.999 ...) es que var_dump
no imprime el número exacto (!), Pero se imprime el número redondeado a n - 2
(o n - 1
) dígitos, donde n dígitos es la precisión del cálculo.Usted puede fácilmente verificar esta:
echo 1.15 * 100; # this prints 115
printf("%.30f", 1.15 * 100); # you 114.999....
echo 1.15 * 100 == 115.0 ? "same" : "different"; # this prints `different'
echo 1.15 * 100 < 115.0 ? "less" : "not-less"; # this prints `less'
Si está imprimiendo flotadores, recuerde: no siempre se ve todos los dígitos cuando se imprime el flotador.
Consulte también la advertencia grande cerca del comienzo de los documentos PHP float.
Esto realmente no tiene nada que ver con PHP y tiene más que ver con cómo todas las computadoras manejan datos de punto flotante. Es posible que desee leer sobre ese tema si no ha encontrado imprecisiones en coma flotante anteriormente. – jmucchiello
@jmucchiello, no estoy de acuerdo. Entiendo cómo las computadoras manejan los datos en coma flotante y es por eso que estoy usando datos enteros en su lugar. Este es un problema de PHP ya que PHP muestra 115 cuando los datos subyacentes son claramente 114.99999999 ... – Josh