如何使用PARI / GP更快地计算出这种主要产品?

时间:2018-04-04 12:06:03

标签: primes pari pari-gp

我想计算产品超过1-1 / p,其中p超过素数达到10 ^ 10

我知道逼近exp(-gamma)/ ln(10 ^ 10),其中gamma是Euler-Mascheroni常数并且是自然对数,但我想计算确切的乘积,看看近似值是多么接近

问题是PARI / GP花费很长时间来计算从大约4.2 * 10 ^ 9到10 ^ 10的素数。 prodeuler-command也需要很长时间。

有没有方法可以加速PARI / GP的计算?

1 个答案:

答案 0 :(得分:1)

我倾向于认为性能问题主要与理性数字有关,而不是产生高达10 ^ 10的质数。

作为快速测试,我跑了

 a(n)=my(t=0);forprime(p=1,n,t+=p);t

使用a(10^10)并在几分钟内计算出来似乎是合理的。

您的请求的相应程序是:

a(n)=my(t=1);forprime(p=1,n,t*=(1-1/p));t

并且这比第一个程序运行得慢得多,所以我的问题是询问是否有办法重新计算计算以避免有理数直到结束?我的表述是否符合您的意图? - 即使是10 ^ 6,这些数字也非常大,所以难怪计算需要花费很长时间,而且这个问题可能与理性的数字有关,而与它们的大小无关。

我用来计算大型产品的一个技巧是分解问题,以便在每个阶段,乘法左右两侧的数字大致相同。例如,计算一个大因子,比如8!计算((1*8)*(2*7))*((3*6)*(4*5))而不是明显的从左到右的方法更有效。

以下是使用精确算术快速尝试执行所需操作的操作。它需要大约8分钟到10 ^ 8,但分子的大小已经是190万位数,因此在内存不足之前它不太可能达到10 ^ 10。 [即使是这个计算,我需要增加堆栈大小]。

xvecprod(v)={if(#v<=1, if(#v,v[1],1), xvecprod(v[1..#v\2]) * xvecprod(v[#v\2+1..#v]))}
faster(n)={my(b=10^6);xvecprod(apply(i->xvecprod(
  apply(p->1-1/p, select(isprime, [i*b+1..min((i+1)*b,n)]))), [0..n\b]))}

使用小数肯定会加快速度。以下运行速度相当快,最高可达10 ^ 8,精度为1000位。

xvecprod(v)={if(#v<=1, if(#v,v[1],1), xvecprod(v[1..#v\2]) * xvecprod(v[#v\2+1..#v]))}
fasterdec(n)={my(b=10^6);xvecprod(apply(i->xvecprod(
  apply(p->1-1.0/p,select(isprime,[i*b+1..min((i+1)*b,n)]))),[0..n\b]))}

使用小数的最快方法是最简单的方法:

a(n)=my(t=1);forprime(p=1,n,t*=(1-1.0/p));t

精度设置为100个十进制数字,这会在2分钟内产生(10 ^ 9),在22分钟内产生(10 ^ 10)。

  

10 ^ 9:0.02709315486987096878842689330617424348105764850

     

10 ^ 10:0.02438386113804076644782979967638833694491163817

使用小数时,分割乘法的技巧不会提高性能,因为数字总是具有相同的位数。但是,我已经离开了代码,因为有可能提高准确性。 (至少在理论上。)

我不确定我是否可以就所需精度的位数给出任何好的建议。 (我更多的是程序员类型,并且倾向于使用整数)。但是,我的理解是每次乘法都有可能丢失1个二进制数字的精度,尽管由于舍入可以平均两种方式,但它不会那么糟糕。鉴于这是超过4.5亿个术语的产物,这意味着所有精度都会丢失。

然而,使用分割计算的算法,每个值只经过大约30次乘法,因此这应该只导致最多30个二进制数字(10个十进制数字)的精度损失,因此使用100位精度应该足够了。令人惊讶的是,我得到了相同的答案,所以简单的天真方法似乎有效。

在我的测试中,我注意到使用forprime比使用isprime要快得多。 (例如,fasterdec版本花了近2个小时,而简单版本需要花费22分钟来获得相同的结果。)类似地,sum(p=1,10^9,isprime(p))大约需要8分钟,而my(t=1);forprime(p=1,10^9,t++);t只需要11秒。