Go Protobuf 精度小数

标签 go protocol-buffers arbitrary-precision

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

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

  • double转换为 float64
  • string这肯定会以自己的方式精确但让我觉得笨拙
  • 类似 decimal来自 mgravell/protobuf-net ?

  • 传统智慧教会我在货币应用程序中避开 float ,但我可能过于小心,因为它是序列化的一个点。

    最佳答案

    如果您 真的需要arbitrary precision ,我担心现在没有正确的答案。有https://github.com/protocolbuffers/protobuf/issues/4406开放,但似乎不是很活跃。如果没有内置支持,你真的需要手动执行序列化,然后使用 stringbytes来存储结果。在string之间使用哪个和 bytes可能取决于您是否需要跨平台/跨库兼容性:如果您需要兼容性,请使用 string并在读取器中使用适当的任意精度类型解析字符串中的十进制表示;如果您不需要它并且您打算使用相同的 cpu 架构和库读取数据,您可能只需使用该库提供的二进制序列化( MarshalBinary/UnmarshalBinary )并使用 bytes .
    另一方面,如果您只需要以适当的精度发送货币值而不需要 任意精度,您可能只需使用 sint64/uint64并使用适当的单位(通常称为 fixed-point numbers )。举个例子,如果您需要用 4 位十进制数字表示以美元为单位的货币值(value),则您的单位将是一美元的 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
    作为旁注,您几乎不应该使用浮点数来表示货币值(value),这是完全正确的。

    关于Go Protobuf 精度小数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50612028/

    相关文章:

    google-app-engine - golang数据存储获取对象

    go - 开始时遇到困难。 `package main` 引发运行时错误 - 索引超出范围?

    java - Map List<String> with Mapstruct 从 Java POJO 到 Protobuf (proto3)

    javascript - JavaScript Number 是任意精度的数字吗?

    php - PHP 中的任意精度数学

    testing - 如何衡量 Golang 集成测试覆盖率?

    java - 将 protobuf3 与一些依赖于 Java 中的 protobuf2 的库一起使用

    encoding - 需要从 urllib2 中找到相当于 openurl() 的请求

    visual-c++ - MSVC++ "official"任意精度库

    go - 如何从 Golang 中的 http 响应中读取压缩数据