我正在进行一些数字运算,这需要高精度算术。我正在使用GNU MP库,according to the GMP manual:
“浮点数或简称浮点数,是一个精度指数有限的任意精度尾数。”
虽然尾数应该具有任意精度,但我仍然遇到精度问题。而不是让我厌倦了我的实际代码,这是一个近乎最小的工作示例,说明了我的问题。代码计算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;
}
答案 0 :(得分: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
答案 1 :(得分: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
所以大约80个十进制数字的公共前缀,或接近256位(64的最大倍数大于199)。
精度为2000时,字符串构造函数的差值为-2.78942e-588,如果从double
初始化则为0(但当然,初始精确度限制为53位,因此意味着两种方式都以相同的方式累积错误。)