Go Protobuf Precision Decimals

时间:2018-05-30 19:20:49

标签: go protocol-buffers arbitrary-precision

如果我想传输任意精度的十进制值,在我的protobuf定义文件中使用的正确scalar type是什么?

我在Go代码中使用shopspring/decimal而不是float64来防止数学错误。在编写我的protobuf文件以便通过gRPC传输这些值时,我可以使用:

传统智慧教会我在货币应用中使用浮动物,但我可能过于小心,因为它是序列化的一个点。

1 个答案:

答案 0 :(得分:0)

如果你真的需要任意精度,恐怕现在没有正确的答案。有 https://github.com/protocolbuffers/protobuf/issues/4406 打开,但似乎不是很活跃。如果没有内置支持,您将确实需要手动执行序列化,然后使用 stringbytes 来存储结果。在 stringbytes 之间使用哪一个可能取决于您是否需要跨平台/跨库兼容性:如果需要,请使用 string 并解析字符串中的十进制表示在阅读器中使用适当的任意精度类型;如果您不需要它并且您打算使用相同的 cpu 架构和库读取数据,您可能只需使用该库提供的二进制序列化 (MarshalBinary/UnmarshalBinary) 并使用bytes

另一方面,如果您只需要发送货币值而不需要任意精度,您可能只需使用 sint64/uint64 并使用适当的单元。举个例子,如果您需要用 4 位十进制数字表示以美元为单位的货币价值,则您的单位将是一美元的 1/10000,例如值 1 表示 $0.0001,值 19900 表示 $1.99,-500000 表示 $-50,依此类推。使用这样的单位,您可以表示 $-922,337,203,685,477.5808 到 $922,337,203,685,477.5807 的范围 - 这对于大多数用途来说应该足够了。您仍然需要手动执行缩放,但它应该是相当简单和可移植的。鉴于上述范围,我建议使用 sint64 更好,因为它也允许您表示负值;仅当您需要额外的正范围而不需要负值时才应考虑 uint64

或者,如果您不介意导入另一个包,您可能想看看 https://github.com/googleapis/googleapis/blob/master/google/type/money.protohttps://github.com/googleapis/googleapis/blob/master/google/type/decimal.proto(顺便实现与上述两个模型非常相似的东西),以及https://pkg.go.dev/github.com/googleapis/go-type-adapters/adapters

处的相关效用函数

作为旁注,您几乎不应该使用浮点数来表示货币值,这是完全正确的。