O tipo float é um tipo de dado usado para representar números reais. Em PHP, assim como em várias outras linguagens, o tipo float possui limites, portanto podem ocorrer perdas de precisão. Em todo caso, vou falar sobre isso a seguir.
Representação de Números Reais
O tipo real, em função de sua aplicação prática, normalmente é representado na forma decimal de forma semelhante como a de um inteiro. A diferença é que no caso de um número real é utilizado o símbolo "." para separar os digitos do valor inteiro dos dígitos do valor das casas decimais. Alguns exemplos a seguir:
$f = 0.0; $f = 1.0; $f = 0.1; $f = 0.0455; $f = 123.0838; $f = -239.134;
Observação: é possível omitir um dos lados do ponto. Caso o valor inteiro seja omitido, ele é considerado como zero. Caso as casas decimais sejam omitidas, é considerada como zero. Alguns exemplos a seguir:
$f = .2; // $f = 0.2; $f = 2.; // $f = 2.0; $f = -.3; // $f = -0.3; $f = -3.; // $f = -3.0;
Em PHP, quando um valor numérico ultrapassa o maior inteiro permitido (ele pode ser descoberto verificando o valor da constante PHP_INT_MAX), ele é automaticamente considerado um número real. Portanto, é possível criar um número real através da notação octal ou hexadecimal, mas é preciso que o valor seja superior a PHP_INT_MAX, conforme o exemplo:
$f = 0xFFFFFFFF; // $f = 4294967295.0;
PHP oferece, ainda, uma forma de representar valores reais através de uma notação com expoente 10. Para isso, é incluído um sufixo em uma representação de número real (com notação decimal). Este sufixo é formado pela letra "e" (sem as aspas e insensível a caixa) seguido por um número inteiro positivo ou negativo, que indica o valor do expoente de 10. Esta notação é util para representar valores muito altos, muito baixos ou muito próximos de zero. Veja alguns exemplos:
$f = 5e3; // 5 * 103 = 5 * 1000 = 5000 $f = -5E3; // -5 * 103 = -5 * 1000 = -5000 $f = 5e-3; // 5 * 10-3 = 5 * (1 / 103) = 5 * (1 / 1000) = 5 * 0,001 = 0,005 $f = -5e-3; // -5 * 10-3 = -5 * (1 / 103) = -5 * (1 / 1000) = -5 * 0,001 = -0,005
Conversão para Float
Int para Float
Um valor inteiro convertido para real apenas continua com o mesmo valor numérico, mas com a representação real.
Bool para Float
O valor true é convertido para o real 1.0, enquanto o valor false é convertido para o real 0.0.
Array para Float
Array vazios são convertidos para o real 0.0, enquanto os arrays não vazios são convertidos para o real 1.0.
String para Float
A conversão de uma string para float é semelhante a que ocorre para o tipo integer. Tenta-se obter a maior porção da string (a partir do primeiro caractere da esquerda) que represente uma forma de criar um valor real na forma decimal. Isso também vale para a notação com expoente 10. Caso nenhuma porção possa ser convertida, então o valor é avaliado como zero. Veja alguns exemplos:
$f = floatval("1.1a"); // $f = 1.1; $f = floatval("1.a"); // $f = 1.0; $f = floatval(".1a"); // $f = 0.1; $f = floatval("5e2"); // $f = 500.0; $f = floatval("1.1e1"); // $f = 11; $f = floatval("1.1e01"); // $f = 11; $f = floatval("-23.4e-1x"); // $f = -0.23; $f = floatval("3 4 5"); // $f = 3.0; $f = floatval("x1"); // $f = 0;
Object para Float
Objetos não podem ser convertidos para real.
Exibição de Números Reais
Nem todos os países usam a mesma notação que PHP usa para criar valores reais (com a notação de "." para indicar o separador de casas decimais). Para isso é preciso tratar o valor para que seja apresentado adequadamente. Existem duas formas básicas para se fazer isso. A primeira, é utilizando a função number_format, onde o programador informa qual o símbolo de casas decimais, o símbolo de milhar e o número de casas decimais:
$f = 2500.7; echo number_format($f, 1, ',', '.'); // Exibe: 2.500,7 echo number_format($f, 2, ',', '.'); // Exibe: 2.500,70 echo number_format($f, 0, ',', '.'); // Exibe: 2.501
A segunda forma, é especificando a localidade através da função setlocale. Esta função modifica a forma como alguns valores são recuperados ou impressos. No caso de valores reais, seria usado da seguinte forma:
$f = 2500.7; setlocale(LC_NUMERIC, 'pt_BR'); echo $f; // Exibe: 2500,7 setlocale(LC_NUMERIC, 'en'); echo $f; // Exibe: 2500.7 // Muda a localidade para o padrao setlocale(LC_NUMERIC, 'C');
Perda de precisão de Números Reais
Ao trabalhar com valores reais, é preciso entender que ele armazena internamente um valor com limitação de casas decimais. Não há como representar uma dizima periótica com um campo do tipo float. Portanto, dividir 1 por 3 (0,333...) não terá o valor exato, a não ser que seja considerado uma quantidade limitada de casas decimais.
Veja um exemplo onde ocorre a perda de precisão:
$f = (0.1 + 0.7) * 10; echo (int)$f;
O código acima exibe 7 ao invés de 8. Isso acontece porque 0.7 é armazenado internamente em uma variável float como sendo 0.69999999999999995559. Quando o valor é somado com 0.1, passa a valer 0.799999999999999 e, multiplicado por 10, passa a valer 7.99999999999999, que, convertido para inteiro, perde as casas decimais.
Uma alternativa é: se você sabe o número de casas decimais que envolvem a conta, multiplique por 10 elevado ao número de casas decimais, converta para inteiro, faça a conta desejada, depois volte a dividir por 10 elevando ao número de casas decimais. Por exemplo, o código acima ficaria assim:
// Considerando uma casa decimal $op1 = 0.7; $op2 = 0.1; // Multiplicar por 10 elevando a 1, que eh 10 $op1 *= 10; $op2 *= 10; // Converter para inteiro $op1 = intval(round($op1)); $op2 = intval(round($op2)); // Realizar a conta desejada $resultado = ($op1 + $op2) * 10; // Dividir por 10 elevando a 1, que eh 10 $resultado = $resultado / 10; echo $resultado; // Exibe 8
Note que é muito complexo fazer isso. Uma alternativa mais simples é fazer contas com strings através da extensão BC.
$precisao = 1; $resultado = bcadd('0.7', '0.1', $precisao); $resultado = bcmul($resultado, '10', $precisao); echo (int)$resultado; // Exibe 8
2 comentários
Tenho $nro1 = 70.456000; $nro2 = 70.480000; (ambos com 6 casas decimais)
Eu gostaria de exibir os nros ignorandos os zeros finais (a direita).....
ou seja, nro1 70,456 e nro 70,48. Tem como?
Sandri, não conheço algo nativo que faça isso. Mas você pode fazer usando estas funções:
rtrim(preg_replace('/0+$/', '', number_format($nro1, 6, ',', '.')), ',')
Postar um comentário
Nota: fique a vontade para expressar o que achou deste artigo ou do blog.
Dica: para acompanhar as respostas, acesse com uma conta do Google e marque a opção "Notifique-me".
Atenção: o blogger não permite inclusão de tags nos comentários, por isso, use algum site externo para postar seu código com dúvidas e deixe o link aqui. Exemplo: pastebin.com