Verdadero PHP

Acerca de   |   ES   |   EN

006c Tipos de datos: números de punto flotante

Un número de punto flotante es cualquier número real. Más que todo, nos referimos a este tipo como "float", pero también se conoce como "double". Se puede intercambiar los dos términos, pero se usa float casi siempre, y es lo que usaremos en estas lecciones. PHP fue escrito en el lenguaje C. En C, sí hay distinción: un double es el doble tamaño de un float, pero en PHP, los dos son el mismo tamaño y los términos significan lo mismo.

Los siguientes son ejemplos de la documentación oficial de PHP sobre números de punto flotante:

<?php
$a = 1.234; 
$b = 1.2e3; 
$c = 7E-10;
$d = 1_234.567; // desde PHP 7.4.0
?>

El tamaño que puede ser su float depende de su sistema. Típicamente, el máximo es el formato 64-bit de IEEE. Eso es aproximadamente 1.8e308 con una precisión de 14 puntos decimales.

No confíe en los números float hasta el último dígito y no los compare directamente por igualdad. Existen otros métodos para manejar tales situaciones: funciones bc math y funciones gmp.

Convertir a float de string

Si el string es un número, por ejemplo “3.1415”, se convierte perfectamente. Si el string no es un número o si no empiece con un número, por ejemplo “abc” o “tra 84.48”, entonces se convierte a 0.

<?php
var_dump((float) "3.1415"); // float (3.1415)
var_dump((float) "3.14is PI"); // float(3.14)
var_dump((float) "XYZ"); // float(0)
var_dump((float) "LMNO 77.77"); // float(0)

// Anote que estos quizá muestran "double()" en vez de "float()".
// Recuerde que en PHP esos son iguales!
?>

Comparando floats

Tenga en cuento la advertencia anterior, pero sí puede comparar tipos de datos float. Como dice la documentación: “Para comprobar la igualdad de valores de punto flotante, se utiliza un límite superior en el error relativo debido al redondeo. Este valor se conoce como el épsilon de la máquina o unidad de redondeo, y es la menor diferencia aceptable en los cálculos.”

<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;

if(abs($a-$b) < $epsilon) {
    echo "verdad";
}
?>

Hablaremos de las operadores de comparación más en lecciones futuros, pero la cosa que debe tomar en cuenta aquí es la técnica. La línea 6 utiliza la función abs() que regresa el valor absoluto de lo se pasa. Luego compara la diferencia con el redondeo de unidades (llamado $epsilon). Esto significa que los dos floats son iguales hasta 5 puntos decimales (en este ejemplo).

Constante especial NaN

Al hacer cálculos con puntos flotantes, es posible que a veces saldrá NaN (no es número — not a number, en inglés) como resultado. Es una constante especial que representa un valor no definido o sin definición en el calculo de puntos flotantes. Cuando compare NaN a cualquier cosa, regresa false. ¡Aun si lo compare a si mismo! Sólo hay una excepción… si lo compare a true.

<?php
var_dump(NaN == 7); // false (comparado a un int)
var_dump(NaN == 7.1); // false (comparado a un float)
var_dump(NaN == "hola"); // false (comparado a un string)
var_dump(NaN == null); // false
var_dump(NaN == false); // false
var_dump(NaN == NaN); // false

var_dump(NaN == true); // true
?>

Es importante entender estas complejidades cuando trabaje con floats.


Recursos


Retos

La rareza del punto flotante

Cuando compare o manipule floats en una computadora, hay dificultades. Esto es porque en el nivel más basico, la computadora está guardando un número decimal usando binario. Puede ver con los siguientes ejemplos:

<?php
// Ejemplo 1
echo 0.7 - 0.2; // salida: 0.5
var_dump(0.7 - 0.2 == 0.5); // salida: false!

// Ejemplo 2 (por sistemas 64-bit)
echo 5.0 - 0.0000000000001; // salida: 4.9999999999999
echo 5.0 - 0.00000000000001; // salida: 5

// Ejemplo 3
var_dump(579.17 * 100); // salida: double(57917)
var_dump((int) (579.17 * 100)); // salida: int(57916)
?>