Go语言规范中关于常量表达式部分的说明:
编译器在计算无类型浮点或复杂常量表达式时可能使用舍入;请参阅常量小节中的实现限制。这种舍入可能导致浮点常量表达式在整数上下文中无效,即使它在使用无限精度计算时是整数,反之亦然。
句子
这种舍入可能导致浮点常量表达式在整数上下文中无效
指向如下内容:
func main() {
a := 853784574674.23846278367
fmt.Println(int8(a)) // output: 0
}
规范中引用的部分不适用于您的示例,因为a
不是常量表达式而是变量,因此int8(a)
正在转换非常量表达式。此转换由Spec:转换,数值类型之间的转换:
当将浮点数转换为整数时,分数被丢弃(截断为零)。
[…在所有涉及浮点数或复数值的非常量转换中,如果结果类型不能表示该值,则转换成功,但结果值依赖于实现。
由于您将非常量表达式a
转换为853784574674.23846278367
,因此小数部分被丢弃,并且由于结果不适合int8
,因此不指定结果,它依赖于实现。
加引号的部分表示,虽然常量的表示精度比内置类型高得多(例如:float64
或int64
),编译器(必须)实现的精度不是无限的(出于实际原因),即使浮点文字可以精确地表示,对它们执行操作也可能使用中间四舍五入,并且可能不会给出数学上正确的结果。
规格包括最小支持精度:
例如:实现限制:尽管数字常量在语言中具有任意精度,但编译器可以使用具有有限精度的内部表示来实现它们。也就是说,每个实现必须:
- 表示至少256位的整数常量。
- 表示浮点常量,包括复数常量的部分,尾数至少为256位,有符号二进制指数至少为16位。
- 如果不能精确地表示整数常量,则给出错误。
- 如果由于溢出而无法表示浮点数或复杂常数,则给出错误。
- 如果由于精度限制而无法表示浮点数或复数常数,则舍入到最接近的可表示常数。
const (
x = 1e100000 + 1
y = 1e100000
)
func main() {
fmt.Println(x - y)
}
这段代码应该输出1
,因为x
比y
大1。在Go Playground上运行它会输出0
,因为常量表达式x - y
是带舍入执行的,因此+1
会丢失。x
和y
都是整数(没有分数部分),所以在整数上下文中结果应该是1
。但是数字是1e100000
,表示它需要大约333000位,这不是编译器的有效要求(根据规范,256位尾号就足够了)。
如果我们降低常数,我们得到正确的结果:
const (
x = 1e1000 + 1
y = 1e1000
)
func main() {
fmt.Println(x - y)
}
输出数学上正确的1
结果。在Go Playground上试试。表示数字1e1000
需要大约~3333位,这似乎是支持的(并且远远高于最低256位要求)。
int8是一个有符号整数,取值范围是-128到127。这就是为什么您在int8(a)中看到意想不到的值的原因。转换。