【发布时间】:2015-11-16 04:27:35
【问题描述】:
我很难弄清楚如何处理我遇到的问题。
作为复杂公式的一部分,我需要计算一个快速溢出双倍的部分,即结果高达 ~ 1.59*10^(1331)(用数学计算)。
当然,这超出了双倍的范围。然后我在考虑使用 long double,在我的gcc 4.6.3 的 linux 系统上是 16 字节。
1) 双精度 (8byte) 的可能范围最大为 10^(308)。我说得对吗,那个 long double 会增加实际精度,但不会增加可能的数值范围?我记得我听说它可以是或者,取决于系统和编译器。真的吗 ?至少当我尝试用 long double 计算我的值时,我仍然得到 NaN。
2.) 我当时正在寻找一种方法来实际计算这些结果,我找到了 GNU gmp。我听说你可以表示非常大的整数,我认为这可能会有所帮助。但是,阅读文档,似乎与
mpz_t x;
mpz_init(x);
mpz_set_*(x,#);
我可以为 gmp 整数数据类型赋值,但为了做到这一点,我可以“仅”选择赋值可以由内置数据类型(如 double 或 (u/s)int)表示的值等等。我发现如何分配真正巨大的数字是使用mpz_set_str() 从字符串中分配数字。
我将如何分配一个复杂计算结果的数字?
简单来说,公式是这样的:
long double res1,res2=0.0;
int a,b;
a=780;
b=741;
float d,d1,o,s; // can be values in [0.01,100]
res1=(2*(pow(b,2)*pow(E,b*(o + s))*(pow(d1,2) + pow(E,a*s)*(-1 + pow(E,a*o)) + pow(d,2)*(-1 + pow(E,a*s))) + pow(a,2)*pow(E,a*(o + s))*(pow(E,b*s)*(pow(E,b*o) + (-1 + d)*(1 + d + b*o)) + (-d + d1)*(d + d1 + b*o + b*d*s)) - a*b*(pow(d1,2)*(pow(E,a*(o + s)) + pow(E,b*(o + s))) + pow(E,a*o + (a + b)*s)*(-2 + 2*pow(E,b*o) - b*o) + d1*pow(E,a*s)*(-pow(E,b*o) + pow(E,a*o)*(1 + b*o)) + pow(d,2)*pow(E,a*s)*(-pow(E,b*o) + pow(E,b*(o + s)) + pow(E,a*o)*(-1 + pow(E,b*s) - b*s)) + d*(-(d1*pow(E,b*(o + s))) + (1 + d1)*pow(E,b*o + a*s) - pow(E,a*s + b*(o + s)) + pow(E,b*s + a*(o + s))*(1 + b*o) + pow(E,a*(o + s))*(-1 - b*o + b*d1*s)))))......;
res2也会是这种,最后需要计算res1/res2,一般会变成很小的数。
我正在考虑拆分公式并将术语添加到 mpg_z 中,以免超出每个术语的双倍范围,但由于公式又长又复杂,这几乎是不可能的。
所以总而言之,问题是,我的中间结果可能会变得如此巨大,以至于没有数据类型能够存储它们,所以我无法将它分配给 mpz 并摆脱这个问题。
我知道我想计算一个双精度值并实际将 mpz_t 用于整数。据我了解,这是存储此类大数据的唯一方法,因为 mpf_t 只能处理浮点类型。老实说,我对gmp 中的表示仍然感到困惑。
任何想法如何解决这个问题?
【问题讨论】:
-
考虑使用所有 mpz_t 变量。丢失整数变量(在我可以看到的代码部分中,它们被提升为双精度数),无论如何使用它们你什么也得不到。从函数的一开始就制作所有的 mpz_t。顺便说一句,你想做什么?
-
看起来你没有做整数运算,所以我会坚持使用 mpf_t 并使用 gmp 提供的浮点运算来实现你的整个公式。
-
这是理论上的群体遗传学,我正在尝试计算给定任意人口分段函数的相互融合时间的时刻
-
上面的cmets还是正确的。如果您想对部分算法使用 GMP,则将 GMP 用于所有算法要容易得多。根据我的经验,GMP 实际上并不比原生整数慢多少。另外,如果你真的在做浮点数学,我可以推荐 MPFR (mpfr.org) 而不是 GMP。
-
您可能希望使用 C++ 接口,以避免为您的公式片段创建任意临时变量。
标签: c gmp outofrangeexception