Open5
Goとほかの言語処理系でfloat64のビットパターンが異なる?
同じIEEE-754式であってもビットパターンが処理系依存で変化するみたい。
Go で 9863.051758 を ビットパターン化すると「4666647884375102119」になるが、
ほかの処理系では「4666647884374999040」となる場合がある。
(ほかのほとんどの数字では合致するのに!)
16進数なら
- A: 0x40C34386A00192A7(4666647884375102119)
- B: 0x40C34386A0000000(4666647884374999040)
二進数なら
- A: 0100000011000011010000111000011010100000000000011001001010100111
- B: 0100000011000011010000111000011010100000000000000000000000000000
+ | exponent | fraction | |
---|---|---|---|
A | 0 | 10000001100 | 0011010000111000011010100000000000011001001010100111 |
B | 0 | 10000001100 | 0011010000111000011010100000000000000000000000000000 |
なんやー有効桁の下位がゼロになっとるー。float32変換を経由してるってことか!
Goのfloat64の文字列化はfloat32に近しい精度しかないがfloat32と同一精度というわけでもないらしい。
float64定数によって、表示やコード上の表現が同じでもfloat32を経由したときのビットパターンが変化するものと変化しないものがある。
その変化したビットパターンはどちらも同じ表示をしちゃうがそういうパターンがまれにあるということ。
うーむ。やはりfloat32/64をmapのキーにするのはよくないな。
表示やコード表記で変換がどうしても挟まるので。
バイナリパケット上のビットパターンが基準ならビットパターンのままキーにすべきですね。
まとめ
- 浮動小数点数の記述や表記は完全に精度全体を表現しているわけじゃない
- 異なるビットパターンが同じ表記になってしまうこともまれにある
- なのでfloat型をユニークキーとして使ってはいけない