math/big: constant 18446744073709551616 overflows int?

Viewed 200

I found some odd looking code in the math/big library and don't understand how it works. I have extracted the constants out into an example:

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)
}

Returns the error:

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

To be clear, I understand why this code doesn't work. What I'm interested in is knowing is why this error doesn't happen when this constant is used in the standard library?

I thought it might be late evaluated (ie _B - 1) but I can see it's literally used in tests. So what value would be used here?

1 Answers

"constant 18446744073709551616 overflows int?" -- Yes.

int depending on the architecture is at least 32 bits. int32 max value is 2147483647 and int64 max value is 9223372036854775807 both of which are not large enough to hold 18446744073709551615.


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

Numeric constants represent exact values of arbitrary precision and do not overflow. Consequently, there are no constants denoting the IEEE-754 negative zero, infinity, and not-a-number values.

A constant may be given a type explicitly by a constant declaration or conversion, or implicitly when used in a variable declaration or an assignment or as an operand in an expression. It is an error if the constant value cannot be represented as a value of the respective type.

In your case, based on the expression in which it is used, the constant value is given the type int, and since it cannot be represented by that type it results in an error.


You could convert the constants to float64 (or uint in the case of _M) if you want the code to compile.

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


For more see: Does Go compiler's evaluation differ for constant expression and other expression

Related