4

私は浮動小数点数を少し遊んでいますが、過去にそれらについて学んだことに基づいて、最終的には次の0.1 + 0.2ようなものになるという事実0.30000000000000004は私を驚かせません。

しかし、私を驚かせるの、整数演算は常に正常に機能し、これらのアーティファクトがないように見えることです。

私はJavaScript(node.jsのChrome V8)でこれに最初に気づきました:

0.1 + 0.2 == 0.3 // false, NOT surprising
123456789012 + 18 == 123456789030  // true
22334455667788 + 998877665544 == 23333333333332 // true
1048576 / 1024 == 1024  // true

C ++(Mac OS Xではgcc)は同じプロパティを持っているようです。

最終的な結果は、整数がちょうど-より良い言葉がないために-機能するということのようです。10進数を使い始めて初めて、物事が不安定になります。

これは、設計の機能、数学的アーティファクト、またはコンパイラとランタイム環境によって行われる最適化ですか?

4

8 に答える 8

4

これは、設計の機能、数学的アーティファクト、またはコンパイラとランタイム環境によって行われる最適化ですか?

これは実数の特徴です。現代代数の定理(高校代数ではなく現代代数。数学専攻は、基本的な計算と線形代数のクラスの後に現代代数のクラスを取ります)は、正の整数bの場合、任意の正の実数rはr=として表すことができると言います。 a * b p、ここでaは[1、b)にあり、pは整数です。たとえば、1024 10 = 1.024 10 * 103。科学的記数法の使用を正当化するのはこの定理です。

その数aは、終端(たとえば、1.0)、繰り返し(1/3 = 0.333 ...)、または非繰り返し(piの表現)として分類できます。ここに端末番号に関する小さな問題があります。任意の端子番号を繰り返し番号として表すこともできます。たとえば、0.999...と1は同じ番号です。この表現のあいまいさは、端末番号として表現できる番号をそのように表現するように指定することで解決できます。

あなたが発見したのは、すべての整数が任意の基数で終端表現を持っているという事実の結果です。

ここでは、コンピューターで実数をどのように表現するかという問題があります。と同じようintに、long long intすべての整数を表すわけではなく、すべての実数を表すわけでもfloatありません。doubleほとんどのコンピューターで実数rを表すために使用されるスキームは、 r = a * 2 pの形式で表すことですが、仮数(または仮数)を特定のビット数に切り捨て、指数p有限数に制限します。 。これが意味するのは、一部の整数は正確に表現できないということです。たとえば、グーゴル(10 100)は整数であり、浮動小数点表現は正確ではありません。グーゴルの基数2の表現は、333ビットの数値です。この333ビットの仮数は52+1ビットに切り捨てられます。

この結果、問題の整数が2 53より大きい場合、整数の場合でも、倍精度演算は正確ではなくなります。2 53〜264unsigned long long int値のタイプを使用して実験を試してください。これらの大きな整数では、倍精度演算はもはや正確ではないことがわかります。

于 2012-10-25T10:16:38.770 に答える
3

私は、Javascriptがすべての数値に倍精度浮動小数点表現を使用することを前提に書いています。

一部の数値、特に。などのすべての整数は、浮動小数点形式で正確に表現されます|x| < 2^53。一部の数値は、特に、バイナリ表現で無限の分数になる0.1や0.2などの分数ではありません。

すべてのオペランドと演算の結果が正確に表現されている場合は、を使用して結果を比較しても安全==です。

関連する質問:

概算としてのみ表現できる2進数の数値はどれですか?

10進数を2進数で正確に表現できないのはなぜですか?

于 2012-10-25T09:13:38.030 に答える
2

表現可能な範囲内の整数はマシンによって正確に表現可能ですが、floatはそうではありません(まあ、それらのほとんど)。

「基本的な整数数学」によって「機能」を理解している場合は、そうです。算術を正しく実装することが機能であると見なすことができます。

于 2012-10-25T08:40:38.140 に答える
2

その理由は、すべての整数(1、2、3、...)を正確に2進形式(0001、0010、0011、...)で表すことができるためです。

0011-0001は常に0010であるため、整数が常に正しいのはそのためです。浮動小数点数の問題は、ポイントの後の部分を正確に2進数に変換できないことです。

于 2012-10-25T08:41:33.680 に答える
1

「動作する」と言うすべてのケースは、指定した数値を浮動小数点形式で正確に表すことができるケースです。0.25、0.5、0.125を加算しても、2進浮動小数点数で正確に表すことができるため、正確に機能することがわかります。

不正確な結果のように見えるものが得られるのは、0.1などにできない値だけです。

于 2012-10-25T08:40:29.840 に答える
1

整数は正確です。これは、不正確さが主に小数の記述方法に起因するためです。また、多くの有理数は、特定の基数に繰り返しのない表現がないためです。

詳細な説明については、 https: //stackoverflow.com/a/9650037/140740を参照してください。

于 2012-11-16T01:37:02.310 に答える
0

この方法は、非常に小さい整数を非常に大きい整数に追加する場合にのみ機能します。その場合でも、両方の整数を「浮動小数点」形式で表現していません。

于 2012-10-25T08:44:35.157 に答える
-1

すべての浮動小数点数を表すことはできません。それはそれらをコーディングする方法によるものです。wikiページは私よりもそれをよりよく説明しています:http://en.wikipedia.org/wiki/IEEE_754-1985。したがって、浮動小数点数を比較する場合は、デルタを使用する必要があります。

myFloat - expectedFloat < delta

表現可能な最小の浮動小数点数をデルタとして使用できます。

于 2012-10-25T08:44:06.687 に答える