PHP int e float
A lojinha da Ana vive de números: quantos cadernos tem no estoque, quanto custa cada um, quanto o cliente vai pagar. O PHP tem dois tipos de número: int, para inteiros (3 cadernos), e float, para números com casas decimais (R$ 12,90). Nesta aula você aprende a escrever os dois, o que acontece quando um número fica grande demais, por que 0.1 + 0.2 não dá exatamente 0.3 e o que o PHP faz quando alguém tenta dividir por zero.
- A diferença entre
intefloat, e quando cada um aparece. - O maior inteiro do PHP (
PHP_INT_MAX) e o que acontece depois dele. - Por que floats são "quase exatos" e como lidar com isso (
round). - Outras formas de escrever números: hexadecimal, octal, binário e
1_000_000. - As três divisões:
/,intdive%(o resto), e ofdiv. - Como testar se algo é número:
is_int,is_float,is_numeric. - O erro
DivisionByZeroError.
Os programas desta aula rodaram com o PHP 8.5 (64 bits) na máquina fictícia da Ana, na pasta ~/site. As contas em si (+, -, *, **, incremento) estão em Operadores Aritméticos.
A ideia: contar e medir
Pense em duas perguntas do dia a dia: "quantos ovos tem na caixa?" e "quanto pesa esse queijo?". Ovos você conta: 1, 2, 12, nunca 2,7 ovos. O queijo você mede: 0,350 kg, 1,2 kg.
int(de integer, "inteiro") é para contar: quantidade, idade, ano, número de páginas. Sem casas decimais.floaté para medir: peso, altura, média, porcentagem. Tem casas decimais.
<?php $ovos = 12; $queijo = 0.35; $inteiroComPonto = 10.0; var_dump($ovos, $queijo, $inteiroComPonto, 5 + 2.0);
$ php tipos.php int(12) float(0.35) float(10) « 10.0 tem ponto: é float, mesmo sem parte decimal float(7) « int + float dá float
Duas regras importantes: o separador decimal é o ponto (0.35, nunca 0,35), e basta um float na conta para o resultado ser float. Para mostrar 0,35 com vírgula ao usuário, use number_format (aula Formatar Números).
1. int: números inteiros
Inteiros podem ser positivos, negativos ou zero: 29, -5, 0. Mas não são infinitos: o PHP guarda cada inteiro em 8 bytes (64 bits), o que dá um limite. O PHP oferece constantes (valores prontos, com nome em maiúsculas; aula Constantes) para você consultar esse limite:
<?php var_dump(PHP_INT_MAX); var_dump(PHP_INT_MIN); var_dump(PHP_INT_SIZE);
$ php limites.php int(9223372036854775807) « o maior int: uns 9,2 quintilhões int(-9223372036854775808) « o menor int int(8) « cada int ocupa 8 bytes
É um número enorme: dá para contar os segundos de quase 300 bilhões de anos. Na prática, você raramente encosta nele. Mas o que acontece se passar?
Passou do limite: o int vira float
<?php var_dump(PHP_INT_MAX + 1); var_dump(PHP_INT_MAX * 2); var_dump(is_float(PHP_INT_MAX + 1));
$ php estouro.php float(9.223372036854776E+18) « não deu erro: virou float float(1.8446744073709552E+19) bool(true)
Em muitas linguagens, passar do maior inteiro faz o número "dar a volta" e virar negativo (o overflow, "transbordamento"). O PHP faz diferente: converte o resultado para float, sem aviso. O E+18 é a notação científica: 9.22...E+18 quer dizer 9,22 × 1018.
O preço disso: um float tem cerca de 15 a 17 dígitos significativos, então os últimos algarismos do número se perdem. Para contas com números gigantes e exatos, o PHP tem as extensões bcmath e gmp, assunto avançado.
2. Outras formas de escrever um inteiro
Além do jeito normal (decimal), o PHP aceita outras bases numéricas. Você vai encontrá-las em cores (0xFF), permissões de arquivo (0o755) e configurações:
| Notação | Começa com | Exemplo | Vale (decimal) |
|---|---|---|---|
| Decimal | 1–9 | 26 | 26 |
| Hexadecimal (base 16) | 0x | 0x1A | 26 |
| Octal (base 8) PHP 8.1+ | 0o | 0o17 | 15 |
| Octal (forma antiga) | 0 | 017 | 15 |
| Binário (base 2) | 0b | 0b1010 | 10 |
| Com separador PHP 7.4+ | — | 1_000_000 | 1000000 |
| Notação científica (float) | — | 1.5e3, 2E-3 | 1500.0, 0.002 |
<?php var_dump(0x1A, 0o17, 017, 0b1010, 1_000_000, 1.5e3, 2E-3);
$ php notacoes.php int(26) int(15) int(15) int(10) int(1000000) float(1500) float(0.002)
Repare: o PHP guarda e mostra tudo em decimal. A notação é só o jeito de escrever no código. O sublinhado em 1_000_000 serve apenas para os olhos (como o ponto em "1.000.000" no português) e some.
Por causa da forma antiga de octal, 017 não é dezessete: é quinze. Nunca escreva zeros à esquerda em números (como num CEP ou num código de produto). Se o "número" tem zeros que importam, ele é texto: "01310-100". Um 08 ou 09 nem é aceito, porque 8 e 9 não existem na base 8:
$ cat zero-esquerda.php <?php var_dump(08); $ php zero-esquerda.php Parse error: Invalid numeric literal in /home/ana/site/zero-esquerda.php on line 2
Invalid numeric literal = "número escrito de forma inválida". Prefira sempre 0o17 quando quiser octal: é impossível confundir.
3. float: números com casas decimais
Qualquer número com ponto ou com e (notação científica) é um float: 4.5, -0.25, 10.0, 1.5e3. O nome vem de floating point ("ponto flutuante"): o computador guarda os algarismos e, separado, a posição do ponto, que pode "flutuar". Isso permite guardar números muito grandes e muito pequenos, mas com uma limitação.
A surpresa: 0.1 + 0.2
<?php var_dump(0.1 + 0.2); var_dump(0.1 + 0.2 == 0.3); echo 0.1 + 0.2, "\n";
$ php precisao.php float(0.30000000000000004) « não é exatamente 0.3! bool(false) « por isso a comparação dá falso 0.3 « o echo arredonda para mostrar e esconde o problema
Não é um defeito do PHP: acontece em JavaScript, Python, Java, em praticamente toda linguagem. O computador guarda os floats em binário (base 2), e alguns números simples em decimal, como 0,1, viram dízimas infinitas em binário, do mesmo jeito que 1/3 vira 0,3333… em decimal. O computador guarda um valor muito próximo, mas não exato. Somando dois "quase", sobra um errinho na 17ª casa.
Repare também na diferença entre var_dump e echo: o var_dump mostra o valor com todos os dígitos necessários; o echo mostra no máximo 14 algarismos significativos, e por isso exibe 0.3. A configuração precision do PHP controla isso. Não confie no echo para investigar floats.
O errinho pode virar um erro grande quando o float é cortado para inteiro:
<?php var_dump((0.1 + 0.7) * 10); var_dump((int) ((0.1 + 0.7) * 10));
$ php corte.php float(7.999999999999999) int(7) « era para ser 8! o (int) corta, não arredonda
(O (int) converte para inteiro jogando fora a parte decimal; veja Conversão de Tipos.)
Como conviver com isso
| Situação | O que fazer |
|---|---|
| Mostrar um resultado | Arredonde: round($x, 2) ou formate com number_format. |
| Comparar dois floats | Arredonde os dois antes (round($a, 2) == round($b, 2)) ou veja se a diferença é minúscula: abs($a - $b) < PHP_FLOAT_EPSILON. |
| Dinheiro | Guarde em centavos, como int: R$ 12,90 vira 1290. Some e multiplique inteiros e só divida por 100 na hora de mostrar. |
| Converter para inteiro | Arredonde primeiro: (int) round($x). |
Arredondar: round, floor, ceil
<?php var_dump(round(0.1 + 0.2, 2)); var_dump(round(0.1 + 0.2, 2) == 0.3); var_dump(round(3.14159, 2)); var_dump(round(2.5)); var_dump(round(-2.5)); var_dump(round(1234.5678, -2)); var_dump(floor(4.9)); var_dump(ceil(4.1));
$ php arredondar.php
float(0.3)
bool(true) « depois de arredondar, a comparação funciona
float(3.14) « 2 casas decimais
float(3) « .5 arredonda para longe do zero…
float(-3) « …nos dois sentidos
float(1200) « casas negativas: arredonda para centenas
float(4) « floor ("chão"): sempre para baixo
float(5) « ceil ("teto"): sempre para cima
- round($x, casas)
- Arredonda para o número de casas pedido (o padrão é 0). O meio (
.5) vai para longe do zero, como na escola. - floor($x)
- "Chão": o maior inteiro menor ou igual (
4.9→4). - ceil($x)
- "Teto" (de ceiling): o menor inteiro maior ou igual (
4.1→5). Útil para "quantas caixas preciso?".
As três devolvem float, mesmo quando o resultado é redondo. Se precisar de int, converta: (int) round($x).
Experimente: troque 0.1 e 0.2 por outros valores (0.5 + 0.25, 1.1 + 2.2, 19.99 * 3). Quais dão um resultado "torto" no var_dump? O round conserta?
<?php $a = 0.1; $b = 0.2; $soma = $a + $b; var_dump($soma); echo $soma, "\n"; var_dump(round($soma, 2));
4. Dividir: /, intdiv, % e fdiv
A Ana tem 17 balas para dividir entre 5 crianças. Dependendo da pergunta, a resposta é diferente:
- "Quanto dá 17 dividido por 5?" → 3,4 (a divisão comum,
/). - "Quantas balas inteiras cada criança recebe?" → 3 (a divisão inteira,
intdiv). - "Quantas sobram?" → 2 (o resto,
%).
<?php var_dump(17 / 5); var_dump(intdiv(17, 5)); var_dump(17 % 5); var_dump(10 / 2); var_dump(10 / 3); echo 10 / 3, "\n";
$ php dividir.php float(3.4) int(3) « intdiv: só a parte inteira int(2) « %: o resto (17 = 5 × 3 + 2) int(5) « divisão exata entre ints dá int… float(3.3333333333333335) « …senão, float 3.3333333333333 « o echo mostra só 14 algarismos
- $a / $b
- Divisão comum. Dá
intse a conta for exata entre inteiros; senão,float. - intdiv($a, $b)
- "Divisão inteira": só a parte inteira do resultado, sempre
int. Só aceita inteiros. - $a % $b
- O "módulo": o resto da divisão inteira. Clássico para saber se um número é par (
$n % 2 == 0). Para floats, usefmod(10.5, 3)(dá1.5).
O sinal do resto segue o primeiro número: -10 % 3 dá -1, e 10 % -3 dá 1. Mais detalhes em Operadores Aritméticos.
Missão: complete o programa usando intdiv e % com as variáveis (não digite 3 e 2 à mão) para mostrar Cada criança: 3 e Sobram: 2. Depois teste com outros valores de $balas.
<?php $balas = 17; $criancas = 5; $cada = 0; // calcule aqui $sobra = 0; // e aqui echo "Cada criança: $cada\n"; echo "Sobram: $sobra\n";
<?php $balas = 17; $criancas = 5; $cada = intdiv($balas, $criancas); $sobra = $balas % $criancas; echo "Cada criança: $cada\n"; echo "Sobram: $sobra\n";
5. Dividir por zero
Na matemática, dividir por zero não tem resposta. No PHP 8, é um erro que para o programa:
<?php echo "Antes\n"; echo 10 / 0; echo "Depois\n";
$ php zero.php
Antes
Fatal error: Uncaught DivisionByZeroError: Division by zero in /home/ana/site/zero.php:3
Stack trace:
#0 {main}
thrown in /home/ana/site/zero.php on line 3
$ echo $?
255 « o "Depois" nunca apareceu
- Fatal error
- Erro fatal: o programa parou aqui.
- Uncaught
- "Não capturado". O PHP lançou um erro e ninguém o tratou. É possível tratar com
try/catch(aula Exceções). - DivisionByZeroError
- O nome do erro: "erro de divisão por zero".
- Division by zero
- A mensagem.
- zero.php:3 … on line 3
- Arquivo e linha.
- Stack trace
- "Rastro da pilha": o caminho de chamadas até o erro. Aqui, só o programa principal (
{main}).
O resto e a divisão inteira também dão o mesmo erro, com mensagens um pouco diferentes:
$ php resto-zero.php « echo 10 % 0;
Fatal error: Uncaught DivisionByZeroError: Modulo by zero in /home/ana/site/resto-zero.php:2
Stack trace:
#0 {main}
thrown in /home/ana/site/resto-zero.php on line 2
$ php intdiv-zero.php « echo intdiv(10, 0);
Fatal error: Uncaught DivisionByZeroError: Division by zero in /home/ana/site/intdiv-zero.php:2
Stack trace:
#0 /home/ana/site/intdiv-zero.php(2): intdiv(10, 0)
#1 {main}
thrown in /home/ana/site/intdiv-zero.php on line 2
A forma de evitar é conferir o divisor antes, com um if: "se o número de crianças for zero, avise; senão, divida".
fdiv: a divisão que não dá erro PHP 8.0+
Para cálculos científicos, o PHP tem fdiv (de float division), que segue a regra dos floats: dividir por zero dá "infinito" (INF) ou "não é um número" (NAN):
<?php var_dump(fdiv(10, 0)); var_dump(fdiv(-1, 0)); var_dump(fdiv(0, 0));
$ php fdiv.php float(INF) « infinito float(-INF) « menos infinito float(NAN) « Not A Number: "não é um número"
Num sistema de loja, você quase nunca quer INF como preço. Prefira conferir o divisor.
6. É número? is_int, is_float, is_numeric
<?php
var_dump(is_int(5));
var_dump(is_int(5.0));
var_dump(is_float(5.0));
var_dump(is_numeric("12"));
var_dump(is_numeric("12.5"));
var_dump(is_numeric("1e3"));
var_dump(is_numeric(" 12"));
var_dump(is_numeric("12 "));
var_dump(is_numeric("12abc"));
var_dump(is_numeric("0x1A"));
var_dump(is_numeric(""));
var_dump(is_numeric("1_000"));
$ php testar.php bool(true) bool(false) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(false) bool(false) bool(false) bool(false)
| Teste | Resultado | Por quê |
|---|---|---|
is_int(5) | true | 5 é int |
is_int(5.0) | false | 5.0 é float, mesmo "redondo" |
is_float(5.0) | true | |
is_numeric("12"), ("12.5"), ("1e3") | true | texto com cara de número |
is_numeric(" 12"), ("12 ") | true | espaços nas pontas são tolerados |
is_numeric("12abc") | false | tem letras depois |
is_numeric("0x1A"), ("1_000") | false | as notações do código não valem em texto |
is_numeric("") | false | texto vazio não é número |
O is_numeric é o teste certo para o que vem de formulários, porque tudo chega como texto. Para validar com mais rigor ("um inteiro entre 1 e 120"), existe o filter_var, em Validar Dados.
Quando dá errado
Fatal error: Uncaught DivisionByZeroError: Division by zero
O que significa: o divisor (o número depois do /, do % ou o segundo do intdiv) valia zero. Muitas vezes é uma variável vazia: uma Undefined variable ou um campo de formulário em branco vira zero numa conta.
Como consertar: mostre o divisor com var_dump antes da linha. Confira com if antes de dividir.
Parse error: syntax error, unexpected token ","
$ cat virgula.php <?php $preco = 4,5; $ php virgula.php Parse error: syntax error, unexpected token "," in /home/ana/site/virgula.php on line 2
O que significa: você escreveu um número com vírgula. Para o PHP, a vírgula separa coisas, não casas decimais.
Como consertar: use ponto: $preco = 4.5;.
false sem motivo
O que significa: é a imprecisão dos floats: 0.1 + 0.2 == 0.3 é false.
Como consertar: arredonde antes de comparar (round($x, 2) == 0.3) ou trabalhe com inteiros (centavos).
O que significa: (int) e intval cortam a parte decimal. Se a conta deu 7.999999999999999, o corte dá 7.
Como consertar: (int) round($x).
Referência rápida
| Nome | O que é / faz | Exemplo → resultado |
|---|---|---|
PHP_INT_MAX, PHP_INT_MIN | Maior e menor int | 9223372036854775807 |
PHP_FLOAT_EPSILON | Menor diferença entre floats perto de 1 | 2.220446049250313E-16 |
round($x, $casas) | Arredonda | round(3.14159, 2) → 3.14 |
floor($x) / ceil($x) | Para baixo / para cima | floor(4.9) → 4 |
$a / $b | Divisão | 17 / 5 → 3.4 |
intdiv($a, $b) | Divisão inteira | intdiv(17, 5) → 3 |
$a % $b | Resto (inteiros) | 17 % 5 → 2 |
fmod($a, $b) | Resto (floats) | fmod(10.5, 3) → 1.5 |
fdiv($a, $b) | Divisão sem erro no zero | fdiv(10, 0) → INF |
is_int, is_float | Testa o tipo | is_int(5.0) → false |
is_numeric($x) | Número ou texto numérico | is_numeric("12.5") → true |
Exercícios
1. O resto
Complete para mostrar o resto de 20 dividido por 6 (que é 2):
2. Duas casas
Complete para arredondar $media com 2 casas decimais:
3. Qual é o tipo de 10 / 4?
4. Quanto vale 017 no PHP?
5. O que acontece com PHP_INT_MAX + 1?
Missão final: a média da turma
Missão: o programa calcula a média de três notas, mas mostra Média: 8.2333333333333. Use round para mostrar a média com uma casa decimal: Média: 8.2.
<?php $nota1 = 7.5; $nota2 = 8; $nota3 = 9.2; $media = ($nota1 + $nota2 + $nota3) / 3; echo "Média: $media\n";
<?php $nota1 = 7.5; $nota2 = 8; $nota3 = 9.2; $media = round(($nota1 + $nota2 + $nota3) / 3, 1); echo "Média: $media\n";
Resumo
intconta (sem casas decimais);floatmede (com ponto). Um float na conta torna o resultado float.- O maior int é
PHP_INT_MAX; passar dele transforma o resultado em float, sem aviso. - Inteiros podem ser escritos em hexadecimal (
0x), octal (0o), binário (0b) e com_como separador. Cuidado com zeros à esquerda. - Floats são aproximados:
0.1 + 0.2dá0.30000000000000004. Arredonde comround, compare com cuidado e guarde dinheiro em centavos. /divide;intdivdá a parte inteira;%dá o resto;fdivdivide sem erro no zero.- Dividir por zero com
/,%ouintdivdáDivisionByZeroErrore para o programa. is_inteis_floattestam o tipo;is_numericaceita texto numérico.