以下是go中的示例代码:
package main
import "fmt"
func mult32(a, b float32) float32 { return a*b }
func mult64(a, b float64) float64 { return a*b }
func main() {
fmt.Println(3*4.3) // A1, 12.9
fmt.Println(mult32(3, 4.3)) // B1, 12.900001
fmt.Println(mult64(3, 4.3)) // C1, 12.899999999999999
fmt.Println(12.9 - 3*4.3) // A2, 1.8033161362862765e-130
fmt.Println(12.9 - mult32(3, 4.3)) // B2, -9.536743e-07
fmt.Println(12.9 - mult64(3, 4.3)) // C2, 1.7763568394002505e-15
fmt.Println(12.9 - 3*4.3) // A4, 1.8033161362862765e-130
fmt.Println(float32(12.9) - float32(3)*float32(4.3)) // B4, -9.536743e-07
fmt.Println(float64(12.9) - float64(3)*float64(4.3)) // C4, 1.7763568394002505e-15
}
A1,B1和C1行之间的结果差异是可以理解的。但是,从A2到C2的魔法来了。 B2和C2都没有匹配A2线的结果。对于行x2(x = A,B或C)也是如此 - 但x2和x4的输出是相同的。
为了确保让我们以二进制形式打印结果。
fmt.Printf("%b\n", 3*4.3) // A11, 7262054399134925p-49
fmt.Printf("%b\n", mult32(3, 4.3)) // B11, 13526631p-20
fmt.Printf("%b\n", mult64(3, 4.3)) // C11, 7262054399134924p-49
fmt.Printf("%b\n", 12.9 - 3*4.3) // A12, 4503599627370496p-483
fmt.Printf("%b\n", 12.9 - mult32(3, 4.3)) // B12, -8388608p-43
fmt.Printf("%b\n", 12.9 - mult64(3, 4.3)) // C12, 4503599627370496p-101
fmt.Printf("%b\n", 12.9 - 3*4.3) // A14, 4503599627370496p-483
fmt.Printf("%b\n", float32(12.9) - float32(3)*float32(4.3)) // B14, -8388608p-43
fmt.Printf("%b\n", float64(12.9) - float64(3)*float64(4.3)) // C14, 4503599627370496p-101
上述代码中的一些事实(bin形式中的一个):
问题来了:
代码已在“go run”和“go build”(go1.0.3)以及该网站上的64位Linux上进行了测试:http://tour.golang.org/
答案 0 :(得分:3)
- 数字常量表示任意精度的值,不会溢出。
- 表示至少256位的整数常量。
- 表示浮点常数,包括复数常量的部分,尾数至少为256位,有符号指数至少为32位。
是的,由编译器编译时间常量。
是的,它们是不同的:涉及更高的精确度。见1.
是的,请参阅1.
最大限度地减少多项浮点常量表达式的浮点错误累积。
当然是的。可以实现更低精度的目标吗?运行时浮点运算本质上是不完美的,不需要从常量表达式中添加更多不精确度就足够了。
答案 1 :(得分:0)
表示浮点常数,包括复数常量的部分,尾数至少为256位,有符号指数至少为32位。
请注意Go 1.8(目前在2017年第四季度发布的测试版,2017年第一季度发布)改变了这一定义:
语言规范现在只要求实现在浮点常量中支持最多16位指数。
这不会影响“gc
”或gccgo
编译器,两者都支持32位指数。
spec
:在常量中需要16位最小指数而不是3216位二进制指数允许的范围大致范围从7e-9865到7e9863,这对于任何实际和假设的常数算法来说都足够了。
此外,直到最近
cmd/compile
无法正确处理非常大的指数;也就是说,任何真正的程序(但是对于探索角落情况的测试)受到影响的几率接近于零。最后,限制最小支持范围可显着降低实际复杂性的区域,这对于新的或替代的符合规范的实现而言并不重要,这些实现不依赖于或不依赖于支持32位的预先存在的仲裁精度算术包指数范围。
这在技术上是一种语言变化,但由于上述原因,这不太可能影响任何真正的程序,当然也不会影响使用gc或gccgo编译器编译的程序,因为它们目前支持最多32位指数。
请参阅issue 13572提及:
在Go 1.4中,编译器拒绝了大于10000的指数(由于知道代码不适用于较大的指数),没有任何用户投诉。
在Go的早期版本中,大型指数无声地被错误处理,再次没有任何用户投诉。