为什么用两种方式转换相同的值,结果却不同?

时间:2019-08-08 12:57:53

标签: go floating-point type-conversion int

相同常量到result => { result.name = result.name.replace(' ', '_'); return result; } 的两种转换返回相同的值,但是当我尝试将这些新值转换为float64时,结果是不同的。

int

我希望前两个... const Big = 92233720368547758074444444 func needFloat(x float64) float64 { return x } func main() { fmt.Println(needFloat(Big)) fmt.Println(float64(Big)) fmt.Println(int(needFloat(Big))) fmt.Println(int(float64(Big))) } 返回相同类型的值

Println

因此,当我将它们转换为fmt.Println(needFloat(Big)) // 9.223372036854776e+25 fmt.Println(float64(Big)) // 9.223372036854776e+25 时,我希望得到相同的输出,但是:

int

2 个答案:

答案 0 :(得分:1)

如果您真正的问题是为什么一次尝试转换为int会产生一个编译时错误消息,而另一次却产生一个非常负的整数,那是因为一个是编译时转换,而另一个是运行时转换。我认为在这些情况下,明确说明您期望什么,可以运行什么,不能运行什么是有帮助的。这是您的代码的Go Playground版本,其中最后一次转换被注释掉了。注释掉它的原因当然是因为它没有编译。

Adrian noted in a comment一样,Big是一个常数,特别是无类型的常数。与Uvelichitel answered一样,常量x(任何类型)可以且仅当且仅当

时可以转换为新的和不同类型的T
  

xrepresentable,其类型为T

(引号部分来自Uvelichitel链接的部分,但我的添加了“ representable”一词的内部链接。)

表达式float64(Big)是一个显式类型转换,其常数为x,因此结果是具有给定值的float64类型的常数。到目前为止,还好:现在我们有92233720368547758074444444作为float64。这会砍掉一些数字:实际的内部表示形式是92233720368547758080000000(请参阅variant with %f directives)。低位...74444444已四舍五入到...80000000。有关四舍五入的原因,请参见“可表示”的链接。

表达式int(float64(Big))是围绕内部显式类型转换的外部显式类型转换。我们已经知道内部类型转换的作用:它产生float64常量92233720368547758080000000.0。外部转换尝试将此新值表示为int,但它不合适,从而产生错误:

./prog.go:18:17: constant 92233720368547758080000000 overflows int

如果已注释掉的行未注释。再次注意,由于进行了内部转换,该值已四舍五入。

另一方面,needFloat(Big)函数调用。调用该函数会将未类型的常量分配给其参数(float64)并获取其返回值(相同的float64,值92233720368547758080000000.0。默认或显式格式指令。返回值是不是一个常数。

类似地,int(needFloat(Big))调用needFloat,它返回与以前相同的float64值(不是常数)。 int显式类型转换尝试在运行时而不是在编译时将此值转换为int 。对于数字类型之间的此类转换,在https://golang.org/ref/spec#Conversions处列出了三个明确的规则,并附有最后的警告。在此,规则2适用:丢弃任何小数部分。但需要注意的是:

  

在所有涉及浮点或复杂值的非恒定转换中,如果结果类型不能表示该值,则转换成功,但结果值取决于实现。

换句话说,没有运行时错误,但是您获得的int值(在这种情况下为-2147483648,它是允许的最小32位整数)取决于实现。这个特定的实现选择使用这个特定的负数作为结果。另一个实现可能选择其他一些数字。 (有趣的是,在操场上,如果我直接转换为uint,我将得到零。如果我转换为int,然后是uint,我将得到预期的0x80000000。)

因此,就是否收到错误而言,主要区别在于您是在编译时通过常量还是在运行时通过运行时转换进行转换。

答案 1 :(得分:0)

int(float64(Big)) //illegal because
  

如果x可以表示为x,则常量x可以转换为T类型   值T

int(needFloat(Big)) //is non-constant expression because of function call
  

非常数值x可以在以下任何一种中转换为类型T   情况:      -x的类型和T都是整数或浮点类型。

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