ホームページ  >  記事  >  バックエンド開発  >  C の浮動小数点演算で予期しない結果が生じるのはなぜですか?また、これらの精度の異常を軽減するにはどうすればよいでしょうか?

C の浮動小数点演算で予期しない結果が生じるのはなぜですか?また、これらの精度の異常を軽減するにはどうすればよいでしょうか?

Barbara Streisand
Barbara Streisandオリジナル
2024-11-04 21:38:02744ブラウズ

Why does C   floating-point arithmetic produce unexpected results, and how can we mitigate these precision anomalies?

C 浮動小数点の精度の異常と解決

C の浮動小数点数は広く使用されているにもかかわらず、精度に限界があります。次のコード スニペットを考えてみましょう:

<code class="cpp">double a = 0.3;
std::cout.precision(20);
std::cout << a << std::endl;

このコードは、予想される 0.3 ではなく 0.2999999999999999889 を出力します。この不一致は、変数 a が 0.3 倍精度浮動小数点数として正確に格納されているのではなく、浮動小数点値の有限表現による近似として格納されているために発生します。

さらに驚くべき動作が発生するのは、次の場合です。 a を 50 回繰り返し追加します:

<code class="cpp">double a, b;
a = 0.3;
b = 0;
for (char i = 1; i <= 50; i++) {
  b = b + a;
};
std::cout.precision(20);
std::cout << b << std::endl;

このコードは驚くべきことに出力します。 15.0 ではなく 15.000000000000014211。これは、加算のたびに近似誤差が蓄積され、元の精度を超える誤差が蓄積されるためです。

精度の異常を解決する

正確な結果を得るには、次のようにします。これは、出力精度を数値型で使用可能な桁数よりも大きく設定しないようにするために重要です。これは、std::numeric_limits クラスを使用して実現できます。

<code class="cpp">#include <iostream>
#include <limits>
int main()
{
        double a = 0.3;
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << a << std::endl;
        double b = 0;
        for (char i = 1; i <= 50; i++) {
                  b = b + a;
        };
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << b << std::endl;
}</code>

このコードは、digits10 メンバー関数を使用して、精度を倍精度浮動小数点数の使用可能な最大桁数 (15) に設定します。

浮動小数点の制限算術

提供されたソリューションは精度誤差を最小限に抑えますが、浮動小数点演算には固有の制限があることを認識することが重要です。ループに数千回の反復が含まれる場合、精度が適切に設定されていても、累積誤差が重大になる可能性があります。このようなシナリオでは、正確な値を維持するには、固定小数点数や有理数などの代替データ型の方が適している可能性があります。

以上がC の浮動小数点演算で予期しない結果が生じるのはなぜですか?また、これらの精度の異常を軽減するにはどうすればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。