在使用Go、MongoDB和Protocol Buffers处理小数时
MongoDB上でNumberDecimal()を使いdecimalで小数を格納していたのだが、それを”mongo-go-driver”を介してDecode()する時に、cannot decode 128-bit decimal into a float32 or float64 typeとエラーが出て困ったので、各々の小数周りの仕様を調べた。
这应该能作为每个小数周围规格的链接集合也很有用。
去
根据 Go 的Numeric types规范,可以使用 float32 和 float64 来处理小数。
协议缓冲区
根据”proto3″的 Language Guide 中的 Scalar Values Type 表,据说在 proto 中使用小数的表示方式是使用 float 和 double,而在 Go 中对应的类型分别是 float => float32,double => float64。
蒙古数据库
在MongoDB上,根据schema定义文档,存在着double和decimal两种类型。根据Bson的规范来看,似乎double是以64位来表示的,而decimal (decimal128)是以128位来表示的。
在MongoDB和Go之间进行交互,一般来说会使用”mongo-go-driver”,但是如果查看其中”go.mongodb.org/mongo-driver/bson”这个部分,可以看到BSON的double会被编码为float64,而128位的decimal会被编码为primitive.Decimal128。
阅读了关于在”mongo-go-driver”中处理Decimal128的方式,可以发现有BigInt()方法可以返回big.Int和指数部分,但是没有将Decimal128转换为Go标准的float64等的方法。
結論: string 是最強的。
今回は、計算したい要件がなく、ただMongoDBから取得したデータをGoを介してProtocol Buffer経由でクライアントに送りたいだけだったので、結局stringにすることにした。他にも、別にMongoDBに入れるのにdecimalであることにこだわりがなければ、doubleを使用することでGo上ではfloat64として扱うことができるので、問題は発生しない。
もし計算したいなら、Decimal128をstringにして、それをさらにfloat64などにするのが良いのか、BigInt()を使って頑張れるのか(”math/big”のFloatに頑張って変換できれば良いのだが)、Decimal128のまま計算する方法があるのかはわかっていない。
不管怎么样,我觉得在任何语言中对小数四舍五入都很麻烦。
(不仅仅是在JavaScript中。。。)