Enteros, flotantes y cadenas numéricas en PHP
Spanish (Español) translation by Ana Paulina Figueroa (you can also view the original English article)
Trabajar con números en PHP parece ser un concepto trivial pero puede ser bastante confuso. Parece sencillo al principio, ya que PHP proporciona una conversión automática de tipos. Por ejemplo, puedes asignar un valor entero a una variable y el tipo de esa variable será entero. En la siguiente línea puedes asignar una cadena a la misma variable y el tipo cambiará a cadena. Desafortunadamente, esta conversión automática algunas veces puede romper tu código.
También hay muchos tipos para valores numéricos. En este tutorial aprenderás sobre los enteros y flotantes en PHP, así como las funciones que pueden ser usadas para determinar el tipo de números con el que estemos tratando y hacer conversiones entre ellos. También aprenderás cómo convertir enteros y flotantes a cadenas numéricas y viceversa.
Diferentes tipos de números en PHP
Enteros
El tipo más básico de número en PHP es el entero. Como quizá sepas, los enteros son números sin una parte decimal. Por ejemplo, 2 es un entero al igual que 235298 o -235298. Por otro lado, 2.0 y 3.58 son flotantes. Los discutiremos con más detalle más adelante.
Un aspecto importante a recordar es que no es necesario que un número sea de tipo int si no tiene una parte decimal. Por ejemplo, 16 * 2.5 es exactamente 40, pero el tipo de este resultado aún será float. Cuando estás multiplicando números, el resultado final será de tipo flotante si al menos uno de los operandos era flotante. No importa si el número final tiene una parte decimal o no.
Además, el máximo valor posible que un entero puede tener en PHP en tu sistema puede obtenerse usando la constante PHP_INT_MAX. Un valor de mayor magnitud que el valor devuelto por PHP_INT_MAX será almacenado como flotante, incluso si se ve como un entero.
Generalmente es de esperar que el resultado de multiplicar dos variables de tipo int sea de tipo int. Sin embargo, esto no es cierto en caso de desbordamiento. La multiplicación de cinco o seis números diferentes puede llevarte fácilmente fuera de los límites del tipo int. Por ejemplo, el resultado de 128*309*32*43*309 es un flotante en mi sistema debido a que excede el valor de PHP_INT_MAX, que es 2147483647.
Puedes usar la función is_int($value) para verificar si un número es de tipo entero. Existen dos alias de esta función llamados is_integer($value) e is_long($value). Ambos devolverán el mismo resultado.
Flotantes
El siguiente tipo más común de número con el que trabajarás es el flotante. A diferencia de los enteros, que eran simplemente números sin puntos decimales en la mayoría de los casos, un número de tipo float puede ser representado de diferentes maneras. Los valores 3.14, 12.0, 5.87E+10 y 3.56E-5 son flotantes.
PHP convertirá un número automáticamente al tipo float cada vez que estén involucrados decimales o números muy grandes. El tipo float comúnmente puede almacenar números con una magnitud aproximadamente igual a 1.7976931348623E+308. Sin embargo, esto depende de la plataforma.
El valor 1.7976931348623E+308 podría parecer un número muy grande (¡y lo es!) pero los flotantes tienen una precisión máxima de aproximadamente 14 dígitos solamente. Cualquier número con más dígitos que esa cantidad perderá su precisión. Esto significa que puedes almacenar un número muy grande, pero no podrás mantener información sobre su valor exacto. En muchos casos, un flotante solamente es una aproximación.
Existen dos funciones que pueden ser usadas para determinar si el valor con el que estás trabajando es un flotante. Estas funciones son is_float() e is_double(). De hecho, is_double() es solamente un alias de is_float(), así que puedes usar cualquiera de las dos opciones y obtener el mismo resultado.
Infinito y NaN
Existen otros dos tipos de valores numéricos con los que quizá tengas que lidiar al escribir programas relacionados con matemáticass. Estos valores de infinito y NaN (no numérico, o not a number en inglés). Ambos de estos valores requieren una pequeña explicación, ya que son diferentes de lo que podrías esperar.
El valor infinito en PHP es diferente del infinito de la vida real. En PHP, cualquier valor numérico superior a aproximadamente PHP_FLOAT_MAX en una plataforma es considerado infinito. Así que, 1.8e308 te devolvería float(INF) en var_dump(). Puedes verificar si un valor numérico es finito o infinito usando las funciones is_finite() e is_infinite().
De manera similar, NaN significa Not a Number (no numérico) pero no comprueba si un valor es numérico o no. El valor NaN se usa para los resultados de operaciones matemáticas que no son posibles en matemáticas. Por ejemplo, log(-1) será NaN. De manera similar, acos(5) también será NaN. Puedes verificar si el valor devuelto por una operación matemática es no numérico usando la función is_nan().
Cadenas numéricas en PHP
De la misma manera en la que PHP cambia dinámicamente el tipo de números diferentes en base a la manera en la que sus valores se usan o asignan, también puede inferir el valor de diferentes cadenas numéricas para que puedas convertirlas a números.
La función is_numeric() puede ayudarte a determinar si una cadena o variable es de hecho numérica o no. Esta función devolverá el valor true para números escritos en notación octal, binaria o hexadecimal. También devolverá true si los números están escritos en notación exponencial, como +16.52e39.
A partir de PHP 7.0.0, cuando envías una cadena a is_numeric(), esta solamente devuelve true si la cadena está compuesta por un signo opcional, algunos dígitos, un decimal opcional y una parte exponencial opcional. Esto significa que una cadena numérica escrita en formato hexadecimal o binario devolverá false a partir de PHP 7.0.0 y versiones posteriores.
PHP convertirá implícitamente cualquier cadena numérica válida a un número cuando surja la necesidad. Los siguientes ejemplos pueden ayudarte a comprender mejor este proceso.
1 |
<?php
|
2 |
|
3 |
$num = "3258712" + 12380; |
4 |
// Output: int(3271092)
|
5 |
var_dump($num); |
6 |
|
7 |
$num = "3258712" + "12380"; |
8 |
// Output: int(3271092)
|
9 |
var_dump($num); |
10 |
|
11 |
$num = 3258712 + "12380"; |
12 |
// Output: int(3271092)
|
13 |
var_dump($num); |
14 |
|
15 |
$num = 3258712 * "12380"; |
16 |
// Output: float(40342854560)
|
17 |
var_dump($num); |
18 |
|
19 |
$num = 3258712 / "12380"; |
20 |
// Output: float(263.2239095315)
|
21 |
var_dump($num); |
22 |
|
23 |
$num = 3258712 / "8"; |
24 |
// Output: int(407339)
|
25 |
var_dump($num); |
26 |
|
27 |
$num = "53.9e4" + 10; |
28 |
// Output: float(539010)
|
29 |
var_dump($num); |
30 |
|
31 |
$num = "398.328" + 10; |
32 |
// Output: float(408.328)
|
33 |
var_dump($num); |
34 |
|
35 |
$num = "398328" + 0xfedd24; |
36 |
// Output: int(17101084)
|
37 |
var_dump($num); |
38 |
|
39 |
$num = 398328 + "0xfedd24"; |
40 |
// Output: int(398328)
|
41 |
var_dump($num); |
42 |
|
43 |
?>
|
Como puedes ver, todas las cadenas numéricas válidas fueron convertidas a sus valores respectivos antes de llevar a cabo sumas u otras operaciones. El tipo de $num al final depende de su valor final.
En el último caso, la cadena hexadecimal "0xfedd24" no es convertida a su valor decimal debido a que PHP 7 no la considera una cadena numérica válida.
Convirtiendo cadenas y flotantes a enteros
De vez en cuando necesitarás convertir un tipo de valores numéricos a otro. PHP tiene diversas funciones y técnicas para hacer esto. La mayor parte del tiempo la conversión será implícita y no tendrás que preocuparte por eso. Sin embargo, si tienes que hacer la conversión explícitamente, las técnicas mencionadas aquí definitivamente te ayudarán.
Puedes usar (int) o (integer) para convertir cualquier valor a un entero. En el caso de los flotantes, los valores siempre serán redondeados hacia cero. Otra manera de convertir cadenas y flotantes a enteros es con la ayuda de la función intval(). Tanto (int) como intval() funcionan exactamente de la misma manera.
1 |
<?php
|
2 |
|
3 |
$float_a = 3598723.8258; |
4 |
$int_cast = (int)$float_a; |
5 |
// Output: 3598723
|
6 |
echo $int_cast; |
7 |
|
8 |
$string_a = "98723.828"; |
9 |
$int_cast = (int)$string_a; |
10 |
// Output: 98723
|
11 |
echo $int_cast; |
12 |
|
13 |
$string_b = "987233498349834828"; |
14 |
$int_cast = (int)$string_b; |
15 |
// Output: 2147483647
|
16 |
echo $int_cast; |
17 |
|
18 |
$float_b = 21474836473492789; |
19 |
$int_cast = (int)$float_b; |
20 |
// Output: -6507212
|
21 |
echo $int_cast; |
22 |
?>
|
Debes tomar en cuenta que la conversión de cadenas de desbordamiento a enteros establecerá el valor final en el valor entero máximo permitido. Sin embargo, la conversión de un flotante cuyo valor sea mayor que el valor entero máximo permitido ¡ocasionará que el valor oscile entre -2147483648 and 2147483647!
En ciertas situaciones es posible que necesites lidiar con números muy grandes sin perder precisión. Por ejemplo, es imposible obtener un resultado preciso al multiplicar 987233498349834828 y 3487197512 usando el operador *. Te dará como resultado 3.4426781992086E+27 después de la conversión a flotante. Calcular la respuesta correcta, que es 3442678199208600117812547936, requerirá el uso de bibliotecas como BCMath. BCMath funciona almacenando números como cadenas y haciendo operaciones aritméticas en ellas manualmente. Solamente recuerda que si usas BCMath estarás trabajando con cadenas en vez de enteros y flotantes.
Ciertas bibliotecas solamente querrán que envíes números de tipo int a sus métodos, pero sin saberlo es posible que les proporciones un valor float. Esto puede pasar debido a que el valor puede parecer un entero al no tener una parte decimal. Esto causaría un error casi con seguridad si la biblioteca usa una función como is_int() para verificar si el número enviado es de tipo entero. En esos casos, siempre es conveniente convertir primero ese número a entero usando ya sea (int) o intval() y luego enviarlo a cualquier función o método de la biblioteca.
Un ejemplo de una situación en la que podría surgir este escenario sería cuando estás trabajando con funciones matemáticas como floor() y ceil(), etcétera. floor() y ceil() siempre devolverán un flotante, ¡incluso si les envías un entero!.
1 |
<?php
|
2 |
|
3 |
$int_a = 15*12; |
4 |
// Output: int(180)
|
5 |
var_dump($int_a); |
6 |
|
7 |
$num = floor($int_a); |
8 |
// Output: float(180)
|
9 |
var_dump($num); |
10 |
|
11 |
?>
|
Un problema con la conversión de flotantes a enteros es que perderás la parte decimal de los números. Esto puede ser deseable en algunos casos y no serlo en otros. En estos casos, puedes usar funciones como floor() y solamente convertir el número a tipo entero si su valor actual es igual al valor devuelto por floor().
1 |
<?php
|
2 |
|
3 |
$number = 16*2.5; |
4 |
|
5 |
if(floor($number) == $number) { |
6 |
$fraction->setNumerator((int)$number); |
7 |
} else { |
8 |
echo 'Did not set the numerator.'; |
9 |
doSomethingElse(); |
10 |
}
|
11 |
|
12 |
?>
|
Digamos que tienes una biblioteca que te permite hacer operaciones aritméticas con fracciones y arroja excepciones cuando envías un número a su método setNumerator() que no es de tipo int. Diversas operaciones podrían convertir un número a tipo flotante, incluso si aún es un entero que está dentro de los límites mínimos y máximos del tipo int. El uso del algo como el código anterior te ayudará a lidiar con esos casos fácilmente.
Consideraciones finales
Este tutorial ha cubierto diferentes maneras en las que PHP almacena números y la forma en la que puedes determinar si un número es de un tipo en particular. Por ejemplo, puedes usar funciones como is_int() e is_float() para determinar el tipo de un número y continuar de acuerdo a eso.
Como viste en el tutorial, PHP soporta la conversión automática de tipos. Esto significa que algunas veces los valores enteros más pequeños, como 5 o 476, pueden haber sido almacenados como flotantes sin que te des cuenta. El uso de estos números en funciones que solamente acepten valores int podría dar como resultado excepciones o errores. Aprendimos que una solución simple a este problema es convertir explícitamente dichos números a int si no tienen una parte decimal y sus valores no cambian al convertirlos.
Después de leer este tutorial, deberás ser capaz de determinar el tipo de un número o el tipo final de un resultado después de usar diversas operaciones empleando funciones predefinidas, y también convertirlos explícitamente a un tipo específico después de hacer algunas verificaciones.
Como siempre, si tienes preguntas o consejos adicionales te invitamos a dejar un comentario.



