Java 什么';计算一系列数字的LCM最有效的算法是什么?

Java 什么';计算一系列数字的LCM最有效的算法是什么?,java,algorithm,optimization,biginteger,lcm,Java,Algorithm,Optimization,Biginteger,Lcm,我环顾四周,发现其他问题都有答案,但没有一个涉及到这个问题的范围,包括,还有 我必须以有效的方式计算大范围数字的LCM。我没有深入研究其他问题,因为它们没有处理与该算法必须处理的数字范围一样大的数字范围 我现在得到的代码可以在90秒内计算出1到350000之间每个数字的LCM。(结果数字约为76000位十进制数字)。我希望最终能够将其扩展到数百万甚至数十亿个元素长的范围 它最终可能会平行化。对于某些算法来说,这一点都不难,而对于其他算法来说,这将更加棘手(例如,如果算法使用当前生成的LCM来计算

我环顾四周,发现其他问题都有答案,但没有一个涉及到这个问题的范围,包括,还有

我必须以有效的方式计算大范围数字的LCM。我没有深入研究其他问题,因为它们没有处理与该算法必须处理的数字范围一样大的数字范围

我现在得到的代码可以在90秒内计算出1到350000之间每个数字的LCM。(结果数字约为76000位十进制数字)。我希望最终能够将其扩展到数百万甚至数十亿个元素长的范围

它最终可能会平行化。对于某些算法来说,这一点都不难,而对于其他算法来说,这将更加棘手(例如,如果算法使用当前生成的LCM来计算其计算的其他部分的素性)

这是:

public静态biginger getLCMOfRange(biginger下限,biginger上限)
{
BigInteger M=BigInteger.1;
大整数t;
//长l=System.currentTimeMillis();
//System.out.println(“计算小于等于“+上限+”的数字的LCM”);
对于(;lower.compareTo(upper)!=1;lower=lower.add(BigInteger.ONE))
{
t=M.gcd(较低);
如果(t.compareTo(较低)==0)
继续;
M=M.乘(低)除(t);
}
//System.out.println(“Done.take”+(System.currentTimeMillis()-l)+“毫秒。LCM是”+M.bitCount()+“位长”);
返回M;
}
请注意,与典型的for循环不同,此函数在[lower,upper]而不是[lower,upper]上运行。此行为是故意的

有一点支持的数学是,某一组数字的LCM是一组素数因子的乘积,从中可以生成任意一个数字,而不需要任何池外的数据。如果我的范围是[1,20],我可以用以下方式表示:

1: 1         6:  3*2      11: 11       16: 2^4
2: 2         7:  7        12: 3*2^2    17: 17
3: 3         8:  2^3      13: 13       18: 3^2*2
4: 2^2       9:  3^2      14: 7*2      19: 19
5: 5         10: 5*2      15: 5*3      20: 5*2^2

LCM{[1,20]}: 2^4*3^2*5*7*11*13*17*19 = 232792560
有没有更有效的方法在如此大的范围内计算LCM

我不在乎有人建议的算法是否占用大量内存,在这种情况下,时间性能比内存性能更重要(也更昂贵)

这不是一个家庭作业问题

问题: 计算非常大范围数字的LCM的最有效方法是什么?该算法需要在非常大的数字范围内运行,因此必须仔细优化

增编1
一个密切相关的问题是:计算一个BigInteger的对数(以另一个BigInteger为基数)最有效的方法是什么?结果值可以被截断为最接近的整数。

这是算法的布局。我假设您总是从1开始:

  • 找到范围内的素数。你可以使用埃拉托斯筛来筛选350000个。对于更大的数字范围,你需要

  • 对于每个素数p,使用对数函数找到pe在范围内的最大指数e。将pe乘以LCM。(优化细节取决于您的实现)

  • 为什么它是正确的

    • 对于p为素数且e>=1形式的数字,由于步骤2,已包含在LCM中,因此pe | LCM
    • 其他数字的形式为N=p1e1p2e2…pnen(其中pi是两两不同的素数,ei>=1),大于或等于piei(对于从1到N的所有i)。由于piei | LCM,由于前面的参数,N | LCM

      • 这是@nhahtdh答案的概括

        第一步,找到所有小于或等于上界的素数

        然后取每个素数p,用基数p表示法记下下限和上限。两个数字中不同的最高数字是需要包含在LCM中的p的指数。如果下限为1,则与另一个答案基本相同


        请注意,此算法的复杂性不取决于范围的长度,而只取决于上限的大小。

        值得注意的是,我可能可以使用素数以某种方式加快计算速度。值得注意的是,我可以使用此数字范围来计算素数:如果gcd(LCM,n)是素数,n小于范围顶部的平方,n必须是素数)。这将让我检查对数子问题在近似线性时间内小于max^2的数字的素数(到LCM的大小):loga(b)=logx(b)/logx(a),其中x可以是任何常数,因此只需除以二进制(或十进制)这两个数字的长度应该给你一个近似值。或者这不够精确吗?@biziclop我需要地板的精确值(a log b base c),其中a、b和c可能都是大整数。虽然在实践中,我可能不会在运行此算法时使用足够大的输入来要求c为大整数。这是我想到的解决方案,但它仅在范围从1开始时有效。要使其适用于从x,y开始的一系列数字,只需要从1,x-1中删除唯一的素数。例如例如,如果范围为14,20,则只需删除20/2=10和14之间的素数。(10,14)。所以你将删除11,13。你不需要删除7,因为它出现在14的素因式分解中。@JustinDanielson我看不出它是如何工作的。例如,如果你的范围是(40,40),你如何找到2的最大指数?@biziclop:我想到了一个适用于任意范围的解决方案,但对于小范围可能并不有效(在这种情况下,素因子分解是一个更好的选择)。第一步是一样的(筛选总是从1开始)。对于第二步:找到p^e,使其成为=下限的最大数字,然后包含在LCM中。否则,找到最大p^e,使p^e+p^e>下限,将p^e包含在LCM中。这可能就是我使用的答案。I