4

高精度の演算が必要な数値処理を行っています。私はGNU MPライブラリを使用しており、GMPマニュアルによると

「浮動小数点数または略して Float は、精度指数が制限された任意精度の仮数です。」

仮数は任意の精度を持つはずですが、まだ精度の問題が発生しています。私の実際のコードであなたを退屈させるのではなく、ここに私の問題を示す最小限に近い作業例を示します。このコードは、9.3^15、9.8^15、および (9.3*9.8)^15 を計算します。私のマシンでは、(9.3^15)*(9.8^15) と (9.3*9.8)^15 の値は 16 桁目以降から異なり始め、この場合は (約) 4.94* のエラーにつながります。 10^13。

どんな助けでも大歓迎です。以下のコード。

#include <gmp.h>
#include <gmpxx.h>

#include <iostream>
#include <iomanip>

int main()
{
    mpf_class x, y, z;
    x = y = z = 1.0;

    for (int i = 0; i < 15; i++)
    {
        x *= 9.3;
        y *= 9.8;
        z *= 9.3*9.8;
    }

    std::cout << z - x*y << std::endl;

    return 0;
}
4

2 に答える 2

2

あなたが見ている問題は、9.3 * 9.8 がおよそ計算されるという事実によるものです。リテラルを mpf_class のインスタンスに変更してください:

mpf_class a, b;
a = 9.3;
b = 9.8;

// ...

x *= a;
y *= b;
z *= a * b;

無限の精度が必要な場合は、代わりに有理数を使用することを検討してください。

#include <gmp.h>
#include <gmpxx.h>

#include <iostream>
#include <iomanip>

int main()
{
    mpq_class x(1), y(1), z(1), a(93, 10), b(98, 10);

    for (int i = 0; i < 15; i++)
    {
        x *= a;
        y *= b;
        z *= (a * b);
    }

    std::cout << z - x*y << std::endl << z << std::endl;

    return 0;
}

版画

0
7589015305950762920038660273144124106674963183136666693/30517578125000000000000000
于 2012-07-22T22:17:59.563 に答える
1

問題は、明示的に精度を設定しないため、デフォルトの精度が得られることです。これは通常(私が思うに)64ビットです。したがって、計算方法が異なると丸めが異なるため、最後のビットで結果が異なります。これにより、約 20 桁が一般的なプレフィックスになります (計算が増えると、差がさらに大きくなる可能性があります)。より高い精度を設定すると、

#include <gmp.h>
#include <gmpxx.h>

#include <iostream>
#include <iomanip>

int main()
{
    mpf_class x(1.0,200), y(1.0,200), z(1.0,200), a("9.3",200), b("9.8",200), c(0,200); 
    c = a*b;

    for (int i = 0; i < 15; i++)
    {
        x *= a;
        y *= b;
        z *= c;
    }

    std::cout << z << "\n" << (x*y) << std::endl;
    std::cout << z - x*y << std::endl;

    return 0;
}

ここで 200 ビット、より正確な結果が得られます。

$ ./a.out 
2.48677e+29
2.48677e+29
-4.80637e-49

したがって、10 進数で約 80 桁、またはほぼ 256 ビット (199 より大きい 64 の最小倍数) の一般的なプレフィックスです。

精度が 2000 の場合、文字列コンストラクターとの差は -2.78942e-588 で、初期化元の場合は 0 ですdouble(もちろん、初期の正確さは 53 ビットに制限されているため、両方の方法でエラーが蓄積されることを意味します)。同じ方法)。

于 2012-07-22T22:34:27.740 に答える