【问题标题】:What is the purpose of arbitrary precision constants in Go?Go 中任意精度常量的目的是什么?
【发布时间】:2019-08-15 15:17:35
【问题描述】:

Go 具有任意大小和精度的无类型精确数字常量。 spec requires 所有编译器都支持至少 256 位的整数和至少 272 位的浮点数(尾数为 256 位,指数为 16 位)。所以编译器需要忠实而准确地表示这样的表达式:

const (
    PI       = 3.1415926535897932384626433832795028841971
    Prime256 = 84028154888444252871881479176271707868370175636848156449781508641811196133203
)

这很有趣......但我找不到任何方法来实际使用任何超过 64 位具体类型 int64uint64float64complex128 的最大精度的常量(其中只是一对float64 值)。即使是标准库 big number types big.Intbig.Float 也不能从大的数字常量初始化——它们必须从字符串常量或其他表达式反序列化。

基本机制相当明显:常量仅在编译时存在,并且必须强制转换为可在运行时表示的某个值才能在运行时使用。它们是一种仅存在于代码中和编译期间的语言结构。您无法在运行时检索常量的原始值;它没有存储在已编译程序本身的某个地址中。

所以问题仍然存在:当大量常量无法在实践中使用时,为什么语言会如此强调支持?

【问题讨论】:

    标签: go constants


    【解决方案1】:

    TLDR; Go 的任意精度常量使您可以使用“实数”数字而不是“装箱”数字,因此可以缓解像溢出、下溢、无穷大极端情况这样的“伪影”。您可以使用更高的精度,只需将结果转换为有限精度,从而减轻中间误差的影响。

    The Go Blog: Constants:(强调是我回答你的问题)

    数值常量存在于任意精度的数值空间中;他们只是普通的数字。但是当它们被分配给一个变量时,该值必须能够适合目标。我们可以声明一个非常大的常量:

    const Huge = 1e1000
    

    ——毕竟这只是一个数字——但我们不能分配它,甚至不能打印它。该语句甚至不会编译:

    fmt.Println(Huge)
    

    错误是,“常量 1.00000e+1000 溢出 float64”,这是真的。 但是Huge 可能有用:我们可以在带有其他常量的表达式中使用它,如果结果可以在float64 的范围内表示,我们可以使用这些表达式的值。语句,

    fmt.Println(Huge / 1e999)
    

    如预期的那样打印10

    以一种相关的方式,浮点常数可能具有非常高的精度,因此涉及它们的算术更准确。math 包中定义的常数比可通过float64 获得。这里是math.Pi的定义:

    Pi    = 3.14159265358979323846264338327950288419716939937510582097494459
    

    当将该值分配给变量时,会丢失一些精度; 分配将创建最接近高精度值的float64(或float32)值。这个sn-p

    pi := math.Pi
    fmt.Println(pi)
    

    打印3.141592653589793

    有这么多可用的数字意味着像Pi/2 这样的计算或其他更复杂的计算可以在分配结果之前带来更高的精度,从而使涉及常量的计算更容易编写而不会丢失精度。这也意味着在常量表达式中不会出现像无穷大、软下溢和NaNs 这样的浮点极端情况。(除以常量零是编译时错误,并且当一切都是数字时,就没有“不是数字”这样的东西。)

    查看相关:How does Go perform arithmetic on constants?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      • 2015-11-03
      • 2014-03-10
      • 2014-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多