Go中的浮点运算

shy*_*cha 4 floating-point go ieee-754 floating-point-precision

这是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

}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

上面代码中的一些事实(bin形式中的一个):

  1. A11行和C11行之间有区别(最后一位-指数之前)。
  2. A12和C12行几乎相同(除指数!!!),在A14和C14行之间可以观察到相同。

问题来了:

  1. 如何计算裸(裸:)数字?(每Axx行中的计算)
  2. 它们是由编译器执行的吗?
  3. 如果是,那为什么又不同呢?优化?
  4. 是否在不同于IEE-754的某些系统中进行计算?
  5. 如果是,为什么呢?
  6. 实现这种方法的准确性是否更高?

代码已在64位linux上的“运行”和“构建”(go1.0.3)下以及该站点上进行了测试:http ://tour.golang.org/

zzz*_*zzz 5

  1. 常数

    • 数字常数表示任意精度的值,并且不会溢出。
    • 用至少256位表示整数常量。
    • 表示浮点常数,包括复数常数的部分,尾数至少为256位,带符号的指数至少为32位。
  2. 是的,由编译器用于编译时间常数。

  3. 是的,它们是不同的:涉及更多的精度。请参阅1。

  4. 是的,请参阅1。

  5. 为使多项项浮点常量表达式的浮点错误的累积最小化。

  6. 当然可以 达到较低的精度可以成为目标吗?运行时浮点运算本质上是不完美的,这就不需要在常量表达式中增加更多的不精确性。