1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GoとMongoDBとProtocol Buffersでの小数の扱い

Last updated at Posted at 2020-02-14

MongoDB上でNumberDecimal()を使いdecimalで小数を格納していたのだが、それを"mongo-go-driver"を介してDecode()する時に、cannot decode 128-bit decimal into a float32 or float64 typeとエラーが出て困ったので、各々の小数周りの仕様を調べた。

それぞれの小数周りの仕様へのリンク集としても役立つはず。

Go

Go上で小数に対応する型は、Numeric typesの仕様によると、float32float64のよう。

Protocol Buffers

"proto3"のLanguage GuideにあるScalar Values Type表によると、proto上での小数表記はfloatdooubleで、それぞれGo上ではfloat => float32double => float64となるらしい。

MongoDB

MongoDB上では、schema定義のドキュメント曰く、doubledecimalが存在する。これはBson Typeにあたるので、Bsonの仕様書を見てみると、どうやら64bitで表現されるのがdoubleであり、128bitで表現されるのがdecimal (decimal128)であることがわかる。

MongoDBとGoの間でやり取りするには、基本的に"mongo-go-driver"を使うことになると思うが、その中の"go.mongodb.org/mongo-driver/bson"についての箇所を見ると、BSONのdoublefloat64に、128-bit decimalprimitive.Decimal128にエンコードされることがわかる。

"mongo-go-driver"でのDecimal128の扱いを読んでみると、BigInt()big.Intとexponential部分を返すメソッドはあるようだが、Decimal128をGo標準のfloat64などに変換するメソッドはないことがわかる。

結論 string 最強

今回は、計算したい要件がなく、ただMongoDBから取得したデータをGoを介してProtocol Buffer経由でクライアントに送りたいだけだったので、結局stringにすることにした。他にも、別にMongoDBに入れるのにdecimalであることにこだわりがなければ、doubleを使用することでGo上ではfloat64として扱うことができるので、問題は発生しない。

もし計算したいなら、Decimal128stringにして、それをさらにfloat64などにするのが良いのか、BigInt()を使って頑張れるのか("math/big"Floatに頑張って変換できれば良いのだが)、Decimal128のまま計算する方法があるのかはわかっていない。

何れにしても、小数周りはどの言語でも辛いんだなぁと思った。
(jsだけじゃなかった。。。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?