使用GMP从公式计算非常大的整数

时间:2013-08-20 11:10:54

标签: c gmp outofrangeexception

我很难弄清楚如何处理我遇到的问题。 作为复杂公式的一部分,我需要计算一个快速溢出的部分,即结果达到~1.59 * 10 ^(1331)(用mathematica计算)。 当然这超出了双倍的范围。然后我考虑使用long double,它在我的linux系统上gcc 4.6.3是16byte。

1)双精度(8byte)的可能范围可达10 ^(308)。我是否正确地说,那么长的双倍会增加实际精度,但不是可能的数值范围?我记得我听说它可以是或者,取决于系统和编译器。真的吗 ?当我尝试用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并摆脱这个问题。

我知道我想计算一个double值,实际上使用mpz_t作为整数。据我所知,这是存储大数据的唯一方法,因为mpf_t只能处理浮点类型。说实话,我仍然对gmp中的表现形式感到困惑。

任何想法如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

问题1 Long double允许处理大于double的数字(在指数和有效位数精度中)。但你必须认为,如果你的目标是存储大整数,你的1e308数量级并不意味着什么;你只需要关心有效数字精度的大小,52/53位(双)或64位(x86扩展精度)。如果你尝试使用更大的整数,你将有一个正确的数量级,但确切的值将会丢失(当使用整数计算时,人们通常比使用近似数字更关心这一点。)

问题2 使用GMP是一个不错的选择。其他图书馆也存在;对于较小的值,我使用了很多libqd,它具有扩展的固定精度并且非常快但这对于你自己的问题来说还不够。现在您的问题是关于设置值:

  • 使用数字的字符串版本通常是一个坏主意(你应该保留它仅用于输入/输出目的);这是一个涉及基础转换和数字化处理的缓慢操作
  • 尽可能多地使用GMP类型进行操作(除非您真正关心速度并完全控制使用本机类型计算值的预期范围
  • 如果你的公式太长,我帮不了多少。但是使用GMP并不是那么难,难道你不能真正转换你的配方吗?您的公式中是否有一些逻辑可以嵌入循环中?也许你可以编写一个快速而肮脏的python脚本,用于使用GMP将公式转换为一段C代码?

现在我不完全理解你为什么要使用mpz_t而不是mpf_t。此类型实现任意长浮点数;你注意到你可以用mpf_set_default_prec设置精度吗?