浮動小数点数

浮動小数点数 (あるいは "float", "double", "実数") は、次の構文により指定できます。

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

PHP 7.4.0 以降の規約(これより前のバージョンでは、アンダースコアは許されませんでした):

LNUM          [0-9]+(_[0-9]+)*
DNUM          ([0-9]*(_[0-9]+)*[\.]{LNUM}) | ({LNUM}[\.][0-9]*(_[0-9]+)*)
EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})

float の大きさはプラットフォーム依存です。ただし、通常はおよそ 10 進数で 14 桁の精度があり、最大値は およそ 1.8e308 (これは 64ビット IEEE フォーマットです) となります。

警告

浮動小数点数の精度

浮動小数点数の精度は有限です。 システムに依存しますが、PHP は通常 IEEE 754 倍精度フォーマットを使います。 この形式は、1.11e-16 のオーダーでの丸め処理で誤差が発生します。 複雑な算術演算をすると、誤差はさらに大きくなるでしょう。そしてもちろん、 いくつかの演算を組み合わせる場合にも誤差を考慮しなければなりません。

さらに、十進数では正確な小数で表せる有理数、たとえば 0.10.7 は、 二進数の浮動小数点数としては正確に表現できません。 これは、仮数部をいくら大きくしても同じです。 したがって、それを内部的な二進数表現に変換する際には、どうしても多少精度が落ちてしまいます。 その結果、不思議な結果を引き起こすことがあります。たとえば、 floor((0.1+0.7)*10) の結果はたいてい 7 となるでしょう。おそらくは 8 を想定していらっしゃるでしょうが、そのようにはなりません。 これは、(この計算結果の) 内部的な値が 7.9999999999999991118... のようになっているからです。

よって、小数の最後の桁を信用してはいけませんし、 小数を直接比較して等しいかどうかを調べてはいけません。より高い精度が必要な場合には、 任意精度数学関数または gmp 関数を代わりに使用してください。

もっと「シンプルな」説明が欲しければ、» floating point guide を見るといいでしょう。"Why don’t my numbers add up? (なんで数字が足されないの?)" というタイトルが付いています。

float への変換

文字列から float への変換

文字列が 数値形式の文字列 の場合、対応する float の値に解決されます。 そうでない場合、ゼロ(0)に変換されます。

他の型から float への変換

文字列以外の値については、 まず最初に int に変換された後、 float に変換されます。 詳細は 整数への変換 を参照下さい。

注意:

型によっては、int に変換したときの動作が未定義のものがあります。 この場合、float に変換する場合の動作も未定義です。

float の比較

先ほど警告したように、浮動小数点数値が等しいかどうかを比較するのには問題があります。 これは、浮動小数点数値の内部表現形式に起因するものです。 しかし、この制限を回避して浮動小数点数値の値を比較する方法もあります。

浮動小数点数値が等しいかどうかを調べるには、比較時の丸め誤差の上界を用います。 この値は計算機イプシロンあるいは丸め単位と呼ばれ、 計算時に扱える最小の差分を表します。

$a$b は、精度 5 桁では等しくなります。

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

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

NaN

数値演算の結果が、定数 NAN で表される値になることがあります。 この定数は、浮動小数点演算における未定義の値あるいは表現不能な値を表します。 この値を他の値と比較すると、緩やかな比較および厳密な比較のいずれでも結果は false になります。 自分自身と比較した場合も含みますが、true と比較した場合は除きます。

NAN はさまざまな値の数を表すものなので、 NAN を他の値を比較してはいけません。たとえ自分自身とであってもです。 チェックをする場合には、かわりに is_nan() を使います。

関連キーワード:  比較, 変換, float, 精度, LNUM, 演算, 表現, 誤差, 小数, 内部