このテスト コード:
$data = array(
12.12234,
1.01
);
foreach($data as $fMyFloat){
echo sprintf('%18.016f', $fMyFloat) . PHP_EOL;
}
...これを私の64ビットコンピューターに出力します:
12.1223399999999994
1.0100000000000000
浮動小数点精度のよく知られた問題に直面しています。基数 10 から基数 2 への整数の変換は非常に簡単 (かつ正確) ですが、基数 10 の浮動小数点数は常に基数 2 で正確に表現できるとは限りません。この問題は PHP に固有のものではありませんが、PHP のマニュアルに警告があります。
浮動小数点数の精度は限られています。システムにもよりますが、PHP は通常、IEEE 754 倍精度形式を使用します。これは、1.11e-16 のオーダーで丸められるため、相対誤差が最大になります。非初等算術演算はより大きな誤差を与える可能性があり、もちろん、いくつかの演算が複合されている場合は誤差の伝播を考慮する必要があります。
さらに、0.1 や 0.7 のように、基数 10 の浮動小数点数として正確に表現できる有理数は、仮数のサイズに関係なく、内部で使用される基数 2 の浮動小数点数として正確に表現できません。したがって、精度をわずかに低下させずに、内部バイナリの対応物に変換することはできません。
このような精度を達成する唯一の方法は、数値を文字列として操作することです。PHP には、文字列との照合が必要な場合に役立つ 2 つの任意精度ライブラリがバンドルされています: GNU Multiple PrecisionとBC Mathです。bcmath を使ったちょっとしたハックを次に示します。
$data = array(
'12.12234',
'1.01'
);
bcscale(16);
foreach($data as $fMyFloat){
echo bcdiv($fMyFloat, 1) . PHP_EOL;
}
ただし、この場合、おそらく単純な文字列関数を使用できます。
$data = array(
'12.12234',
'1.01'
);
foreach($data as $fMyFloat){
list($a, $b) = explode('.', $fMyFloat);
echo $a . '.' . str_pad($b, 16, 0) . PHP_EOL;
}