Open5

Goとほかの言語処理系でfloat64のビットパターンが異なる?

NoboNoboNoboNobo

同じIEEE-754式であってもビットパターンが処理系依存で変化するみたい。
https://go.dev/play/p/Rqo682FNdxM

Go で 9863.051758 を ビットパターン化すると「4666647884375102119」になるが、
ほかの処理系では「4666647884374999040」となる場合がある。
(ほかのほとんどの数字では合致するのに!)

NoboNoboNoboNobo

16進数なら

  • A: 0x40C34386A00192A7(4666647884375102119)
  • B: 0x40C34386A0000000(4666647884374999040)

二進数なら

  • A: 0100000011000011010000111000011010100000000000011001001010100111
  • B: 0100000011000011010000111000011010100000000000000000000000000000

https://ja.wikipedia.org/wiki/IEEE_754

+ exponent fraction
A 0 10000001100 0011010000111000011010100000000000011001001010100111
B 0 10000001100 0011010000111000011010100000000000000000000000000000

なんやー有効桁の下位がゼロになっとるー。float32変換を経由してるってことか!

NoboNoboNoboNobo

Goのfloat64の文字列化はfloat32に近しい精度しかないがfloat32と同一精度というわけでもないらしい。

float64定数によって、表示やコード上の表現が同じでもfloat32を経由したときのビットパターンが変化するものと変化しないものがある。

https://go.dev/play/p/EiSXAftREF9

その変化したビットパターンはどちらも同じ表示をしちゃうがそういうパターンがまれにあるということ。

NoboNoboNoboNobo

うーむ。やはりfloat32/64をmapのキーにするのはよくないな。
表示やコード表記で変換がどうしても挟まるので。
バイナリパケット上のビットパターンが基準ならビットパターンのままキーにすべきですね。

NoboNoboNoboNobo

まとめ

  • 浮動小数点数の記述や表記は完全に精度全体を表現しているわけじゃない
  • 異なるビットパターンが同じ表記になってしまうこともまれにある
  • なのでfloat型をユニークキーとして使ってはいけない