2011年4月17日日曜日

PHPの浮動小数点の精度は・・・あれれ?

このエントリーをはてなブックマークに追加
Pocket

どうも最近のPHP(5.2.7と5.3以降)の浮動小数点の処理は、一定以上の桁数で直感的な値を返して来ないようになっているらしい。

浮動小数点は処理系で精度が変わるものだし、実用上は14桁もあれば十分な事が多いが、一部のマニア級PHPerの混乱を招いているようだ。

例1. 1000000000000000.123を四捨五入すると1000000000000000.123になるのは仕様です(`・ω・´)キリッ

詳細は「PHPの新しいround関数にバグをみつけた」に詳しいが、一般的なコンピューティングの常識と反する四捨五入のルールをPHPは持っている。

最初、浮動小数点などそんなものだと思ったのだが、C (gcc 4.4.3)とJava 1.6.0_24とPython 2.6.5は1000000000000000.0を返すので、PHPの動きが奇妙な事が分かる。なお、気付いた人はバグだと報告をしたのだが、「正しく計算しようとすると無限ループするので仕様です(`・ω・´)キリッ」と言うのが結論のようだ。

PHP simplifies the round implementation by giving up more or less around when the accuracy falls below one. This is indeed a bit lazy even though the units digit is not accurate; without checking the algorithm/history maybe the purpose is to avoid the algorithm doesn't terminate due to adding numbers >=1 having no effect in the result.

PHPの中の人曰く「仕様です(`・ω・´)キリッ」。

例2. 53桁にするとオーバーフローするので、printfで浮動小数点は最大40桁までしか表示できないのは仕様です(`・ω・´)キリッ

Bug #53918の話なのだが、「Status: Wont fix」で動いている気配が無いので、恐らく仕様と言う事になるのだと思う。

I'd just add this is not as simple as changing the MAX_FLOAT_PRECISION define, as values larger than around 512 (the value of NUM_BUF_SIZE) will result in a buffer overflow.

精度の話ではなく、表示桁数の問題な気もするが、諦めているのは変わらない。

実用上は問題ないけど・・・

かなり高い精度でないと問題が発覚しない上、PHPで画像処理等を行う場合は外部モジュールに依存するため、現実的に問題が出るケースを考える方が大変だ。実用上は問題ない。そもそも値によっては、正しくIEEE754を実装していても、9007199254740993のように、10進数の16桁で精度を超える事もある。10進数で19桁の精度が期待されているとも思えない。

どうもPHPの四捨五入の処理が5.2.7と5.3以降で変化したらしく、その影響で精度が犠牲になったようだ。それも言語仕様としては、一つのアプローチなのだとは思う。しかし、場合によっては混乱をもたらしそうな仕様であるため、リファレンス等に精度は他の言語に比べて限定的だと明記するべきだ。

なお、文句あるならパッチを送れと言われているので、PHPハッカーの皆さんはぜひ御参戦を。

In any case, feel free to propose a patch.

0 コメント:

コメントを投稿