29

浮動小数点の不正確さを、コンピュータは無限に賢明で正確だといまだに考えている新米プログラマーや素人にどう説明しますか?
正確ではあるが無味乾燥な説明よりも、アイデアをうまく​​伝えていると思われるお気に入りの例や逸話はありますか?
これはコンピュータ サイエンスの授業でどのように教えられていますか?

4

7 に答える 7

26

基本的に、人々が浮動小数点数で遭遇する 2 つの主要な落とし穴があります。

  1. スケールの問題。各 FP 数値には、数値の全体的な「スケール」を決定する指数があるため、非常に小さい値または非常に大きい値を表すことができますが、それに専念できる桁数は限られています。スケールの異なる 2 つの数値を加算すると、大きいスケールに合わせる方法がないため、小さい方の数値が「食べられる」場合があります。

    PS> $a = 1; $b = 0.0000000000000000000000001
    PS> Write-Host a=$a b=$b
    a=1 b=1E-25
    PS> $a + $b
    1
    

    この場合のアナロジーとして、大きなプールと小さじ 1 杯の水を思い浮かべることができます。両者は大きさが大きく異なりますが、個々に大まかにどれくらいの大きさなのかを簡単に把握することができます。ただし、小さじ 1 杯をプールに注ぐと、ほぼプールが水で満たされた状態になります。

    (これを学んでいる人が指数表記に問題がある場合は、値1などを使用することもできます100000000000000000000。)

  2. 次に、2 進表現と 10 進表現の問題があります。のような数値0.1は、限られた数の 2 進数では正確に表すことができません。ただし、一部の言語ではこれがマスクされます。

    PS> "{0:N50}" -f 0.1
    0.10000000000000000000000000000000000000000000000000
    

    ただし、数値を繰り返し加算することで、表現エラーを「増幅」できます。

    PS> $sum = 0; for ($i = 0; $i -lt 100; $i++) { $sum += 0.1 }; $sum
    9,99999999999998
    

    ただし、これを適切に説明するための適切な類推は思いつきません。正確な値を取得するには、小数部の末尾で 3 を無期限に繰り返す必要があるため、1 / 3をほぼ 10 進数でしか表すことができないのは、基本的に同じ問題です。

    同様に、2 進数の分数は、2 分の 1、4 分の 1、8 分の 1 などを表すのに適していますが、10 分の 1 のようなものは、2 進数の無限に繰り返されるストリームを生成します。

  3. 次に、別の問題がありますが、大量の数値計算を行っていない限り、ほとんどの人はそれに遭遇しません。しかし、彼らはすでに問題について知っています。多くの浮動小数点数は単に正確な値の近似であるため、これは、実数 r の特定の近似fに対して無限に多くの実数r 1r 2、...が正確に同じ近似にマップされる可能性があることを意味します。 . それらの数字は一定の間隔にあります。r minがfとなるrの最小可能値であり、 r maxが最大可能値であるとしましょう。これが保持されるrの場合、間隔 [ r min , r max ] が得られ、その間隔内の任意の数値が実際の数値rになる可能性があります。

    ここで、その数値に対して計算 (足し算、引き算、掛け算など) を実行すると、精度が失われます。すべての数値は単なる概算であるため、実際にはintervalで計算を実行しています。結果も間隔になり、近似誤差は大きくなるだけで、間隔が広がります。その計算から単一の数値が返される場合があります。ただし、これは、元のオペランドの精度と計算による精度の低下を考慮して、可能な結果の間隔からの1 つの数値にすぎません。

    そのようなことは区間演算と呼ばれ、少なくとも私にとっては大学の数学コースの一部でした。

于 2010-01-20T10:12:17.460 に答える
8

base-10 システムがまったく同じ問題を抱えていることを彼らに示してください。

1/3 を底 10 の 10 進数表現として表現してみてください。正確に表現することはできません。

したがって、「0.3333」と書くと、多くのユースケースでかなり正確な表現が得られます。

しかし、それを分数に戻すと、「3333/10000」になり、「1/3」とは異なります

1/2 などの他の分数は、基数 10 の有限 10 進数表現で簡単に表すことができます: "0.5"

現在、基数 2 と基数 10 は本質的に同じ問題に悩まされています。どちらも、正確に表現できない数を持っています。

基数 10 では 1/10 を基数 2 で "0.1" として表すことに問題はありませんが、"0.000110011.." で始まる無限の表現が必要になります。

于 2010-01-20T12:23:51.110 に答える
6

素人への説明としてはどうですか。コンピュータが数値を表す方法の 1 つは、個別の単位を数えることです。これらはデジタルコンピュータです。整数の場合、小数部分のないもの、現代のデジタル コンピューターは 2 の累乗を数えます: 1、2、4、8. ,,, 桁の値、2 進数、何とか、何とか、何とか 分数の場合、デジタル コンピューターは 2 の逆べき乗を数えます: 1/2、1/4、1/8、... 問題は、多くの数がこれらの逆べき乗の有限数の和では表現できないことです。より多くの桁の値 (より多くのビット) を使用すると、これらの「問題のある」数値の表現の精度が向上しますが、ビット数が限られているため、正確に取得することはできません。一部の数値は、無限のビット数では表現できません。

スヌーズ...

OK、容器の中の水の量を測りたいのですが、計量カップはフルカップ、ハーフカップ、クォーターカップの 3 つしかありません。最後のフル カップを数えた後、カップの 3 分の 1 が残っているとします。ただし、利用可能なカップの組み合わせを正確に満たすわけではないため、それを測定することはできません. ハーフ カップには満たせず、クォーター カップからのオーバーフローは小さすぎて何も満たせません。1/3 と 1/4 の差です。この誤差は、他の測定値からの誤差と組み合わせると悪化します。

于 2010-01-20T12:13:10.667 に答える
2

C での別の例

printf (" %.20f \n", 3.6);

信じられないほど与える

3.60000000000000008882

于 2011-05-13T07:46:40.803 に答える
2

パイソンでは:

>>> 1.0 / 10
0.10000000000000001

一部の分数が 2 進数で正確に表現できない理由を説明してください。一部の分数 (1/3 など) と同様に、基数 10 では正確に表すことができません。

于 2010-01-20T10:14:48.317 に答える
1

これが私の簡単な理解です。

問題: 値 0.45 を float で正確に表すことができず、0.450000018 に切り上げられます。何故ですか?

回答: 45 の int 値はバイナリ値 101101 で表されます。値を 0.45 にするためには、45 x 10^-2 (= 45 / 10^2) を取ることができれば正確ですが、それは不可能なので10 の代わりに基数 2 を使用する必要があります。

したがって、10^2 = 100 に最も近い値は 128 = 2^7 になります。必要なビットの総数は 9 です。値 45 の場合は 6 (101101) + 値 7 の場合は 3 ビット (111) です。次に、値は 45 x 2^-7 = 0.3515625 です。今、あなたは深刻な不正確さの問題を抱えています。0.3515625 は 0.45 にほとんど近くありません。

この不正確さを改善するにはどうすればよいでしょうか。値 45 と 7 を別の値に変更できます。

460 x 2^-10 = 0.44921875 はどうですか。現在、460 には 9 ビット、10 には 4 ビットを使用しています。その後、少し近くなりますが、それでもそれほど近くはありません。ただし、最初の目的の値が 0.44921875 の場合、近似なしで正確に一致します。

したがって、値の式は X = A x 2^B になります。A と B は、正または負の整数値です。明らかに、数値が高いほど精度が高くなりますが、値 A と B を表すビット数が制限されていることがわかっているためです。float の合計数は 32 です。Double は 64 で、Decimal は 128 です。

于 2013-04-16T08:01:51.533 に答える
0

9999999.4999999999 を a に変換してから afloatに戻すと、奇妙な数値が見られるかもしれませんdouble。結果は 10000000 として報告されますが、その値は明らかに 9999999 に近く、9999999.499999999 は 9999999 に正しく丸められます。

于 2013-02-05T03:02:02.177 に答える