数学/大:常量 18446744073709551616 溢出 int?

问题描述

我找到了一些 odd looking code in the math/big library,但不明白它是如何工作的。我已将常量提取到示例中:

package main

import (
    "fmt"
    "math/bits"
)

const (
    _S = _W / 8 // word size in bytes

    _W = bits.UintSize // word size in bits
    _B = 1 << _W       // digit base
    _M = _B - 1        // digit mask
)

func main() {
    fmt.Println(_S,_W,_B,_M)
}

返回错误

bug/example.go:17:13: constant 18446744073709551616 overflows int
bug/example.go:17:13: constant 18446744073709551615 overflows int

明确地说,我明白为什么这段代码不起作用。我感兴趣的是知道为什么在标准库中使用此常量时不会发生此错误

我认为它可能会被延迟评估(即 _B - 1),但我可以看到它是 literally used in tests。那么这里会使用什么值?

解决方法

“常量 18446744073709551616 溢出 int?” -- 是的。

int 取决于架构,至少为 32 位。 int32 最大值为 2147483647int64 最大值为 9223372036854775807,两者都不足以容纳 18446744073709551615


https://golang.org/ref/spec#Constants

数字常量代表任意精度的精确值,并且做 不溢出。因此,没有常数表示 IEEE-754 负零、无穷大和非数字值。

常量可以通过常量声明显式指定类型或 转换,或隐式用于变量声明或 赋值或作为表达式中的操作数。 这是一个错误,如果 常量值不能表示为各自的值 类型。

在您的情况下,根据使用它的表达式,常量值的类型为 int,并且由于它不能由该类型表示,因此会导致错误。


如果您希望代码能够编译,您可以将常量转换为 float64(或 uint,在 _M 的情况下)。

package main

import (
    "fmt"
    "math/bits"
)

const (
    _S = _W / 8 // word size in bytes

    _W = bits.UintSize // word size in bits
    _B = 1 << _W       // digit base
    _M = _B - 1        // digit mask
)

func main() {
    fmt.Println(_S,_W,float64(_B),uint(_M))
}

https://play.golang.org/p/AVT5FPHinT3


更多信息请参见:Does Go compiler's evaluation differ for constant expression and other expression