2017-11-09 11 views
2

なぜGoで次のように等しくないのですか?これはバグですか、それとも設計上のものですか?それが仕様であれば、なぜこれが起こり、このタイプの動作はどこに文書化されていますか?なぜ、浮動小数点の乗算とリテラルの違いとGoの変数が異なるのですか?

https://play.golang.org/p/itEV9zwV2a

package main 

import (
    "fmt" 
) 

func main() { 
    x := 10.1 

    fmt.Println("x == 10.1:  ", x == 10.1) 
    fmt.Println("x*3.0 == 10.1*3.0:", x*3.0 == 10.1*3.0) 
    fmt.Println("x*3.0:   ", x*3.0) 
    fmt.Println("10.1*3.0:   ", 10.1*3.0) 
} 

生成し:

x == 10.1:   true 
x*3.0 == 10.1*3.0: false 
x*3.0:    30.299999999999997 
10.1*3.0:   30.3 

注同じ浮動小数点演算は、単に異なる構文を使用して、行われていること。それではなぜ結果が違うのですか?私は、の例のように10.1*3.030.29999...に等しくなると思います。

+0

[浮動小数点数は壊れていますか?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) –

+0

Ken、ありがとうございます。これは同じ問題ではないと私は考えています。なぜなら、その問題は、よく知られている浮動小数点数学の精度に関する問題が多言語であるからです。ここでは、同じ浮動小数点演算が実行されていますが、構文が異なるだけです。それでも結果は異なります。明確にするために、 'x * 3.0'の例のように' 10.1 * 3.0'が '' 30.299999 ... 'になると期待します。 –

+2

「同じ浮動小数点演算が実行されています」というステートメントは、間違ったところです。 – hobbs

答えて

5

Goの定数および数値リテラルは、型指定されておらず、無制限の精度を持ちます。特定の型として格納する必要がある瞬間に、その型の境界が適用されます。したがって、x := 10.1を宣言すると、そのリテラルはfloatに変換され、精度が失われます。しかし、具体的には10.1*3.0を実行すると完全精度が得られます。

この記事の「浮動小数点数」ヘッダーを参照してください。 https://blog.golang.org/constants

数値定数は任意の精度の数値空間に存在します。彼らは は普通の数字です。しかし、変数に代入するときは、 の値が宛先に収まる必要があります。

const Huge = 1e1000 

結局のところ、しかし、ちょうど数だ、我々はそれを割り当てるかさえ、それを印刷することはできません - つまり:我々は非常に大きな値と 定数を宣言することができます。この文もコンパイルされません。

fmt.Println(Huge) 

を誤差は、 真である、「一定の1.00000e + 1000のfloat64をオーバーフロー」されます。しかし、巨大なものが役に立つかもしれません: の他の定数を持つ式でそれを使用し、結果が でfloat64の範囲で表現できる場合は、それらの式の値を使用します。

これが実際にどのようにして、特に与えられたHugeの場合、わかりません。

+0

興味深い。これは、特定の定数や定数がfloat64(10.1や.1など)で正確に表現できない場合に、Goが警告をスローすることを期待しています。私。 10.1は本当に "float64"、または任意の長さの浮動小数点数に "適合"できません。おそらく警告が非常に一般的であるため、これを行わないという設計上の決定がありました。 –

+1

コンパイラはそれらを 'big.Float's(または' big.Int'sまたは 'big.Rat's)として保存します。 GoのコンパイラはGoで書かれていることを覚えておいてください。 – hobbs

+0

BTW:10.1に近い[binary32](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)は10.100000381 ... – chux

3

The Go Programming Language Specification

Constants

数値定数は、任意の精度の正確な値を表し、 ないオーバーフローを行います。したがって、 IEEE-754の負のゼロ、無限大、および非数の値を表す定数はありません。

実装上の制限:数値定数は言語で任意の の精度を持ちますが、コンパイラは精度が限定された の内部表現を使用してそれらを実装できます。それによると、すべての 実装がなければならない:

  • は、少なくとも256ビットで整数定数です。

  • は、少なくとも256ビットの仮数と少なくとも16ビットの符号付きバイナリ 指数と、 複素定数の部分を含む浮動小数点定数を表します。

  • 整数定数 を正確に表すことができない場合は、エラーを指定してください。

  • オーバーフローのために浮動小数点または複合語の 定数を表現できない場合はエラーを返します。 浮動小数点または複素定数を表すことができない場合による精度の限界に最も近い表現定数に

  • ラウンド。

Numeric types

数値型は、整数のセットまたは浮動小数点値を表します。 事前宣言アーキテクチャに依存しない浮動小数点数値型 は、次のとおり

float32  the set of all IEEE-754 32-bit floating-point numbers 
float64  the set of all IEEE-754 64-bit floating-point numbers 

定数は、任意精度演算のためにコンパイル時にパッケージmath/bigを使用します。変数は、浮動小数点演算のためにハードウェアによって提供されることが多いIEEE-754を使用します。

+0

確定的な回答があります!私はちょうど破棄した私の答えに編集でこのようなコンパイル時の算術を推測しようとしていた:) – RayfenWindspear

+0

ありがとう。これは、コンパイラが精度*の制限のために浮動小数点定数*を表現できない場合には警告またはエラーをスローしないことも具体的に説明しています(ただし、オーバーフローの場合はエラーが発生します)。 –

関連する問題