这是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 形式的一个):
- A11 和 C11 行之间存在差异(最后一位数字 - 就在指数之前)。
- A12 和 C12 行几乎相同(除了指数!!!),在 A14 和 C14 行之间可以观察到相同的情况。
问题来了:
- 如何计算裸(裸 :))数字?(每个 Axx 行中的计算)
- 它们是由编译器/其他执行的吗?
- 如果是,那么它们为什么不同?优化?
- 它们是在某些不同于 IEE-754 的系统中计算的吗?
- 如果是,为什么会这样?
- 实现更准确的精度证明这种方法是合理的吗?
代码已在“go run”和“go build”(go1.0.3)下的 64 位 linux 上进行了测试,也在该站点上进行了测试:http: //tour.golang.org/