Números de ponto flutuante (também conhecidos como "floats", "doubles" ou "números reais") podem ser especificados utilizando qualquer uma das seguintes sintaxes:
<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
?>
Formalmente:
LNUM [0-9]+ DNUM ([0-9]*[\.]{LNUM}) | ({LNUM}[\.][0-9]*) EXPONENT_DNUM [+-]?(({LNUM} | {DNUM}) [eE][+-]? {LNUM})
O tamanho de um número de ponto flutuante é dependente de plataforma, sendo o máximo de ~1.8e308 com uma precisão de 14 dígitos decimais um valor comum (número de 64 bits no formato IEEE).
Números de ponto flutuante tem precisão limitada. Embora dependa do sitema, o PHP geralmente utiliza o sistema de precisão dupla do IEEE 754, que terá uma precisão máxima devida a arredondamentos da ordem de 1.11e-16. Operações mátemáticas incomuns poderão incorrer em erros maiores, fora que a propagação de erros precisa ser considerada quando várias operações forem realizadas.
Além disso, números racionais que tem representação exata em números em base 10, como 0.1 ou 0.7, não possuem representação exata em ponto flutuante na base 2 (o formato utilizado internamente), não importanto o tamanho da mantissa. Portanto não existe conversão para o formato interno sem uma pequena perda de precisão. Isso pode ocasionar resultados confusos: por exemplo, floor((0.1+0.7)*10) normalmente retornará 7, em vez do resultado esperado 8, porque a representação interna final será algo como 7.9999999999999991118....
Então, nunca confie em resultados com números de ponto flutuante até a última casa e nunca compare números de ponto flutuante em igualdades. Se você realmente precisar de alta precisão, você pode utilizar as funções matemáticas de precisão arbitrária ou as funções relacionadas ao gmp.
Para uma explicação "simples" dessa questão, veja » o guia sobre ponto flutuante, que também tem o título alternativo de "Porque meus números não somam direito?".
Para informações sobre a conversão de strings para floats, veja a seção entitulada Conversão de Strings para números. Para valores de outros tipos, o valor é primeiro convertido para inteiro e então para float. Veja a seção Convertendo para inteiros para mais informações. No PHP 5, um aviso é emitido se você tentar converter um object para um float.
Como notado acima, testar números de ponto flutuante com igualdade é probelmático, por causa da maneira como são armazenados internamente. Entretanto existem maneiras de fazer comparações com números de ponto flutuante que contornam essas limitações.
Para testar números de ponto flutuante, utilize um "valor de erro máximo" na comparação utilizada. Esse valor é também chamado de epsilon, ou erro de unidade, e deve ser a diferença máxima aceitável no resultado dos cálculos.
$a and $b serão considerados iguais até o 5º dígito de precisão.
<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;
if(abs($a-$b) < $epsilon) {
echo "iguais";
}
?>
Algumas operações numéricas podem resultar em valores representados pela constante
NAN
. Esse resultado representa um valor indefinido
ou não representável nos cálculos de ponto flutuante. Qualquer
comparação deste valor com qualquer outro, inclusive ele mesmo, terá
como resultado FALSE
.
Como o NAN
representa um resultado irrepresentável,
NAN
não deve ser comparado com outros valores, incluindo
si mesmo, o correto sendo a utilização da função is_nan().