4

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 形式の 1 つ):

  1. 行 A11 と C11 (最後の桁 - 指数の直前) には違いがあります。
  2. 行 A12 と C12 はほとんど同じです (指数を除いて!!!)、同じことが行 A14 と C14 の間で観察できます。

そして、ここで質問が来ます:

  1. 裸の (裸の :)) 数値の計算はどのように実行されますか? (すべての Axx 行での計算)
  2. それらはコンパイラなどによって実行されますか?
  3. はいの場合、なぜそれらは異なるのですか? 最適化?
  4. それらは、IEE-754 とは異なるシステムで計算されますか?
  5. はいの場合、なぜそうですか?
  6. より正確な精度を達成することは、そのようなアプローチを正当化しますか?

コードは、「go run」と「go build」(go1.0.3) の両方で 64 ビット Linux でテストされており、次のサイトでもテストされています: http://tour.golang.org/

4

2 に答える 2

5
  1. 定数:

    • 数値定数は、任意の精度の値を表し、オーバーフローしません。
    • 256 ビット以上の整数定数を表します。
    • 浮動小数点定数 (複素定数の一部を含む) を、少なくとも 256 ビットの仮数部と少なくとも 32 ビットの符号付き指数で表します。
  2. はい、コンパイル時定数のコンパイラによって。

  3. はい、それらは異なります。より精度が必要です。1を参照してください。

  4. はい、1 を参照してください。

  5. 複数項の浮動小数点定数式の浮動小数点エラーの蓄積を最小限に抑えるため。

  6. もちろんはい。より低い精度を達成することを目標にすることはできますか? 実行時の浮動小数点演算が本質的に不完全であることで十分であり、定数式からさらに不正確さを加える必要はありません。

于 2013-08-05T11:25:24.677 に答える