アカウント名:
パスワード:
http://svn.php.net/viewvc/php/php-src/trunk/Zend/zend_strtod.c?r1=3070... [php.net]
変数に volatile を付け足すだけの修正で直ったらしいんだけど、どういう最適化が原因で無限ループになるの?
インテルマシン以外でも起きるのかなこれ? インテルマシンでだけ起きるなら、浮動小数点の内部表現形式が(IEEE754の64ビットじゃなくて)80bitであることが原因かも(volatileが付くとたぶんいちいち64ビットに直すコードになるはず)。
正規化数から非正規化数への境界のところで起きてるっていうのはそのとおりだと思うけど。
> 文字列からdoubleへの変換で問題になるんだから80bitは関係ないと思う。
関係あるんですよそれが。今回の問題がまさにそれだったかはわからないけど。ちゃんと変換しようと思うと、10進表現を2進数表記に直した時の仮数部の最後の1ビットを決めるために、そこより下の方の桁も正確に求める必要があります(でないとどっちに丸めていいかわからない)。そのへんは該当コードからも参照されてるClingerのPLDI90のペーパー[1]で議論されてるんですが、真面目にやろうとすると無限精度多倍長整数演算が必要になるんですな。これは、計算の途中結果を丸めてしまうと、最後に仮数部の有効数字でも丸めるので二重丸めが生じるせいです。
で、無限多倍長演算は重いんで、なるべくdoubleの範囲で計算して、誤差がやばそうな場合に無限多倍長演算に切り替えるってことをやるんですが、演算誤差の上限を正確に評価しないとならないんで、仮数部のビット数に依存するんですわ。
もちろんそこまで気にしないでいいっていう用途はあります。libcのstrtodなどはナイーブなアルゴリズムだと思う。それだと、浮動小数点数の書き出し→読み込みを繰り返すと丸めによって次第に値がドリフトしてく可能性があるんですが、それが問題にならないことも多いでしょう。ただ、phpはClingerのペーパーを参照して自前で実装するくらい気合いを入れてるんで、真面目にやろうとしてたんだと思います。
[1] http://www.cesura17.net/~will/Professional/Research/Papers/howtoread.pdf [cesura17.net]
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
皆さんもソースを読むときに、行と行の間を読むような気持ちで見てほしい -- あるハッカー
リリースされたパッチ (スコア:0)
http://svn.php.net/viewvc/php/php-src/trunk/Zend/zend_strtod.c?r1=3070... [php.net]
変数に volatile を付け足すだけの修正で直ったらしいんだけど、どういう最適化が原因で無限ループになるの?
Re: (スコア:1, 興味深い)
インテルマシン以外でも起きるのかなこれ? インテルマシンでだけ起きるなら、浮動小数点の内部表現形式が(IEEE754の64ビットじゃなくて)80bitであることが原因かも(volatileが付くとたぶんいちいち64ビットに直すコードになるはず)。
Re: (スコア:0)
アンダーフローしたので0にしたかったのに、処理をミスったんでしょ。
ここ [sun.com]のIEEE754倍精度の正の最小正規数を見ると"2.2250738585072014e-308"だけど、
問題の"2.2250738585072011e-308"は最後の桁が3小さいからね。
Re:リリースされたパッチ (スコア:5, 参考になる)
正規化数から非正規化数への境界のところで起きてるっていうのはそのとおりだと思うけど。
> 文字列からdoubleへの変換で問題になるんだから80bitは関係ないと思う。
関係あるんですよそれが。今回の問題がまさにそれだったかはわからないけど。ちゃんと変換しようと思うと、10進表現を2進数表記に直した時の仮数部の最後の1ビットを決めるために、そこより下の方の桁も正確に求める必要があります(でないとどっちに丸めていいかわからない)。そのへんは該当コードからも参照されてるClingerのPLDI90のペーパー[1]で議論されてるんですが、真面目にやろうとすると無限精度多倍長整数演算が必要になるんですな。これは、計算の途中結果を丸めてしまうと、最後に仮数部の有効数字でも丸めるので二重丸めが生じるせいです。
で、無限多倍長演算は重いんで、なるべくdoubleの範囲で計算して、誤差がやばそうな場合に無限多倍長演算に切り替えるってことをやるんですが、演算誤差の上限を正確に評価しないとならないんで、仮数部のビット数に依存するんですわ。
もちろんそこまで気にしないでいいっていう用途はあります。libcのstrtodなどはナイーブなアルゴリズムだと思う。それだと、浮動小数点数の書き出し→読み込みを繰り返すと丸めによって次第に値がドリフトしてく可能性があるんですが、それが問題にならないことも多いでしょう。ただ、phpはClingerのペーパーを参照して自前で実装するくらい気合いを入れてるんで、真面目にやろうとしてたんだと思います。
[1] http://www.cesura17.net/~will/Professional/Research/Papers/howtoread.pdf [cesura17.net]