英文:
Go integer overflow settings in commandline and playground
问题
这个程序在我的机器上运行良好(go1.2.1 linux/amd64):
package main
import "fmt"
const bigint = 1<<62
func main() {
fmt.Println(bigint)
}
但是在 Go Playground 上运行时,会出现溢出错误 - http://play.golang.org/p/lAUwLwOIVR
看起来我的构建配置为整数常量使用了 64 位,而 Playground 配置为 32 位。
但是规范中说实现必须至少给常量提供 256 位的精度?
另请参阅我的另一个问题中的代码 - scanner 标准包中的代码:
const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
由于空格是 32,这在 32 位的 Playground 上根本无法工作。
这是怎么回事?
英文:
This program runs fine one my machine (go1.2.1 linux/amd64):
package main
import "fmt"
const bigint = 1<<62
func main() {
fmt.Println(bigint)
}
But with the go playground, it gives overflow error - http://play.golang.org/p/lAUwLwOIVR
It seem that my build is configured with 64 bits for integer constans, playground configured with 32 bits.
But spec say that implementation must give at least 256 bits of precision for constants?
Also see code in my other question -- the scanner standard package has code:
const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
Since space is 32, this don't work on 32-bit playground at all.
How can this be?
答案1
得分: 4
一般常量
常量本身在精度上没有限制,但在代码中使用时会转换为适当的类型。根据规范:
常量可以通过常量声明或转换显式地指定类型,也可以在变量声明、赋值或表达式中隐式地指定类型。 如果常量值无法表示为相应类型的值,则会出现错误。例如,3.0 可以赋给任何整数或浮点类型,而 2147483648.0(等于 1<<31)可以赋给 float32、float64 或 uint32 类型,但不能赋给 int32 或 string 类型。
因此,如果你有以下代码:
const a = 1 << 33
fmt.Println(a)
你将会得到一个溢出错误,因为整数常量的默认类型 int
在32 位环境中无法容纳值 1 << 33
。如果你将常量转换为 int64
,在所有平台上都没有问题:
const a = 1 << 33
fmt.Println(int64(a))
Scanner
常量 GoWhitespace
并未直接在扫描器中使用。在 Scanner
类型中使用的 Whitespace 属性 是 uint64
类型,而 GoWhitespace
被赋值给它:
s.Whitespace = GoWhitespace
这意味着你处理的是一个 uint64
值,而 1 << ' '
(即 1 << 32
)是完全有效的。
示例(在 play 上):
const w = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
c := ' '
// fmt.Println(w & (1 << uint(c))) // 会导致溢出错误
fmt.Println(uint64(w) & (1 << uint(c))) // 正常工作
英文:
Constants in general
Constants itself are not limited in precision but when used in code they are converted to a suitable type.
From the spec:
> 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. For instance, 3.0 can be given any integer or any floating-point type, while 2147483648.0 (equal to 1<<31) can be given the types float32, float64, or uint32 but not int32 or string.
So if you have
const a = 1 << 33
fmt.Println(a)
you will get an overflow error as the default type for integer constants int
can't hold the value 1 << 33
on 32 bit environments. If you convert the constant to int64
everything's fine on all platforms:
const a = 1 << 33
fmt.Println(int64(a))
Scanner
The constant GoWhitespace
is not directly used in the scanner.
The Whitespace attribute used in the Scanner
type is of type uint64
and GoWhitespace
is assigned to it:
s.Whitespace = GoWhitespace
This means you deal with a uint64
value and 1 << ' '
(aka. 1 << 32
) is perfectly valid.
Example (on play):
const w = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
c := ' '
// fmt.Println(w & (1 << uint(c))) // fails with overflow error
fmt.Println(uint64(w) & (1 << uint(c))) // works as expected
答案2
得分: 1
根据nemo的说法,你可以给常量指定一个类型。只需指定int64
,它就可以正常工作
package main
import "fmt"
const bigint int64 = 1<<62
func main() {
fmt.Println(bigint)
}
链接:http://play.golang.org/p/yw2vsvMigk
英文:
As stated by nemo, you can give a type to your constant. Just specify int64
and it works fine
http://play.golang.org/p/yw2vsvMigk
package main
import "fmt"
const bigint int64 = 1<<62
func main() {
fmt.Println(bigint)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论