MongoDB上でNumberDecimal()
を使いdecimal
で小数を格納していたのだが、それを"mongo-go-driver"を介してDecode()
する時に、cannot decode 128-bit decimal into a float32 or float64 type
とエラーが出て困ったので、各々の小数周りの仕様を調べた。
それぞれの小数周りの仕様へのリンク集としても役立つはず。
Go
Go上で小数に対応する型は、Numeric typesの仕様によると、float32
とfloat64
のよう。
Protocol Buffers
"proto3"のLanguage GuideにあるScalar Values Type表によると、proto上での小数表記はfloat
とdoouble
で、それぞれGo上ではfloat => float32
、double => float64
となるらしい。
MongoDB
MongoDB上では、schema定義のドキュメント曰く、double
とdecimal
が存在する。これはBson Typeにあたるので、Bsonの仕様書を見てみると、どうやら64bitで表現されるのがdouble
であり、128bitで表現されるのがdecimal (decimal128)
であることがわかる。
MongoDBとGoの間でやり取りするには、基本的に"mongo-go-driver"を使うことになると思うが、その中の"go.mongodb.org/mongo-driver/bson"についての箇所を見ると、BSONのdouble
はfloat64
に、128-bit decimal
はprimitive.Decimal128
にエンコードされることがわかる。
"mongo-go-driver"でのDecimal128の扱いを読んでみると、BigInt()
でbig.Int
とexponential部分を返すメソッドはあるようだが、Decimal128
をGo標準のfloat64
などに変換するメソッドはないことがわかる。
結論 string 最強
今回は、計算したい要件がなく、ただMongoDBから取得したデータをGoを介してProtocol Buffer経由でクライアントに送りたいだけだったので、結局string
にすることにした。他にも、別にMongoDBに入れるのにdecimal
であることにこだわりがなければ、double
を使用することでGo上ではfloat64
として扱うことができるので、問題は発生しない。
もし計算したいなら、Decimal128
をstring
にして、それをさらにfloat64
などにするのが良いのか、BigInt()
を使って頑張れるのか("math/big"のFloat
に頑張って変換できれば良いのだが)、Decimal128
のまま計算する方法があるのかはわかっていない。
何れにしても、小数周りはどの言語でも辛いんだなぁと思った。
(jsだけじゃなかった。。。