Javascript 计算lcm(i,j)、i和j之和从1到k的最有效的方法是什么?
问题:Javascript 计算lcm(i,j)、i和j之和从1到k的最有效的方法是什么?,javascript,algorithm,performance,math,lcm,Javascript,Algorithm,Performance,Math,Lcm,问题: [ 62.085 ms] pdec init 18888 KBytes [ 0.685 ms] k= 1000 sum= 183011304660 [ 1.373 ms] k= 2000 sum= 2926354006228 [ 2.072 ms] k= 3000 sum= 14805042797184 [ 2.781 ms] k= 4000 sum= 46781822900688 [
[ 62.085 ms] pdec init 18888 KBytes
[ 0.685 ms] k= 1000 sum= 183011304660
[ 1.373 ms] k= 2000 sum= 2926354006228
[ 2.072 ms] k= 3000 sum= 14805042797184
[ 2.781 ms] k= 4000 sum= 46781822900688
[ 3.539 ms] k= 5000 sum= 114218125116052
[ 4.756 ms] k= 6000 sum= 236808736848248
[ 5.223 ms] k= 7000 sum= 438721136165016
[ 6.806 ms] k= 8000 sum= 748454504589824
[ 7.645 ms] k= 9000 sum= 1198740116138576
[ 8.424 ms] k= 10000 sum= 1827127167830060
[ 9.303 ms] k= 11000 sum= 2675130127257140
[ 10.292 ms] k= 12000 sum= 3788610508835184
[ 10.220 ms] k= 13000 sum= 5218119174379260
[ 10.736 ms] k= 14000 sum= 7019284675919704
[ 10.782 ms] k= 15000 sum= 9249622447024312
[ 13.937 ms] k= 16000 sum= 11973761092807672
[ 14.610 ms] k= 17000 sum= 15260078673441888
[ 14.535 ms] k= 18000 sum= 19179420697925096
[ 15.512 ms] k= 19000 sum= 23809411309067844
[ 15.049 ms] k= 20000 sum= 29232792766430776
[ 15.454 ms] k= 21000 sum= 35530729593528460
[ 19.366 ms] k= 22000 sum= 42798909693505916
[ 19.164 ms] k= 23000 sum= 51128789507207824
[ 17.958 ms] k= 24000 sum= 60615343952225808
[ 18.378 ms] k= 25000 sum= 71367596207492300
[ 22.220 ms] k= 26000 sum= 83490183930172416
[ 22.565 ms] k= 27000 sum= 97093514169469316
[ 21.821 ms] k= 28000 sum= 112296054697946652
[ 24.109 ms] k= 29000 sum= 129222336308688284
[ 24.484 ms] k= 30000 sum= 147985909450776556
[ 23.518 ms] k= 31000 sum= 168726314083539724
[ 24.437 ms] k= 32000 sum= 191573248859171168
[ 25.810 ms] k= 33000 sum= 216665462512674040
[ 26.562 ms] k= 34000 sum= 244144733826449780
[ 25.961 ms] k= 35000 sum= 274165636445073084
[ 26.890 ms] k= 36000 sum= 306861019309280956
[ 27.347 ms] k= 37000 sum= 342403256303560068
[ 28.250 ms] k= 38000 sum= 380951178712974600
[ 28.792 ms] k= 39000 sum= 422654544640465536
[ 32.039 ms] k= 40000 sum= 467702202175553120
[ 31.689 ms] k= 41000 sum= 516261770711667188
[ 32.103 ms] k= 42000 sum= 568493102008765720
[ 33.605 ms] k= 43000 sum= 624601491354014924
[ 33.251 ms] k= 44000 sum= 684766511634347904
[ 38.647 ms] k= 45000 sum= 749168090843424836
[ 34.710 ms] k= 46000 sum= 818010181586572760
[ 36.381 ms] k= 47000 sum= 891505184775229460
[ 35.670 ms] k= 48000 sum= 969815208006099344
[ 36.745 ms] k= 49000 sum= 1053194632366715464
[ 39.265 ms] k= 50000 sum= 1141860626298697932
[ 41.430 ms] k= 51000 sum= 1235961937510193376
[ 39.108 ms] k= 52000 sum= 1335793856714706980
[ 39.395 ms] k= 53000 sum= 1441568696460268148
[ 41.918 ms] k= 54000 sum= 1553459252290960280
[ 40.703 ms] k= 55000 sum= 1671762162244218552
[ 41.705 ms] k= 56000 sum= 1796724219557144384
[ 43.305 ms] k= 57000 sum= 1928541735647080528
[ 49.717 ms] k= 58000 sum= 2067474716400847492
[ 43.599 ms] k= 59000 sum= 2213789303836196316
[ 48.271 ms] k= 60000 sum= 2367722439679998864
[ 45.474 ms] k= 61000 sum= 2529554127958058476
[ 47.711 ms] k= 62000 sum= 2699556160225194044
[ 50.947 ms] k= 63000 sum= 2877966575602455352
[ 53.505 ms] k= 64000 sum= 3065104550449828668
[ 54.559 ms] k= 65000 sum= 3261217251285430196
[ 53.066 ms] k= 66000 sum= 3466580213396622284
[ 51.004 ms] k= 67000 sum= 3681481683988726580
[ 52.176 ms] k= 68000 sum= 3906300655499965688
[ 52.597 ms] k= 69000 sum= 4141140842108345608
[ 54.037 ms] k= 70000 sum= 4386474829016834456
[ 55.015 ms] k= 71000 sum= 4642634007103668512
[ 56.036 ms] k= 72000 sum= 4909694650694395656
[ 56.753 ms] k= 73000 sum= 5188180625623422844
[ 56.944 ms] k= 74000 sum= 5478395966863778240
[ 58.519 ms] k= 75000 sum= 5780503390808063112
[ 58.851 ms] k= 76000 sum= 6095030347012208488
[ 59.481 ms] k= 77000 sum= 6422238822380824088
[ 59.821 ms] k= 78000 sum= 6762431127210826000
[ 60.474 ms] k= 79000 sum= 7115946997843513388
[ 62.483 ms] k= 80000 sum= 7483237599224918568
[ 62.773 ms] k= 81000 sum= 7864354728203024788
[ 63.597 ms] k= 82000 sum= 8259936085084243856
[ 63.737 ms] k= 83000 sum= 8670356746307209408
[ 65.268 ms] k= 84000 sum= 9095726603620478688
[ 66.408 ms] k= 85000 sum= 9536717580904610040
[ 66.726 ms] k= 86000 sum= 9993536125103095688
[ 67.575 ms] k= 87000 sum= 10466432130003173312
[ 68.633 ms] k= 88000 sum= 10956004885713459408
[ 68.506 ms] k= 89000 sum= 11462647299842391920
[ 69.760 ms] k= 90000 sum= 11986403043182154584
[ 70.185 ms] k= 91000 sum= 12528192303586301056
[ 71.192 ms] k= 92000 sum= 13088114114334229944
[ 72.118 ms] k= 93000 sum= 13666442859056921956
[ 72.514 ms] k= 94000 sum= 14263784093996812372
[ 73.450 ms] k= 95000 sum= 14880480246958258764
[ 75.154 ms] k= 96000 sum= 15516955556268238668
[ 75.907 ms] k= 97000 sum= 16173675941972720104
[ 76.416 ms] k= 98000 sum= 16851041998775635308
[ 76.931 ms] k= 99000 sum= 17549420431062508128
[ 77.511 ms] k=100000 sum= 18269345553999897648
我的解决方案:
[ 62.085 ms] pdec init 18888 KBytes
[ 0.685 ms] k= 1000 sum= 183011304660
[ 1.373 ms] k= 2000 sum= 2926354006228
[ 2.072 ms] k= 3000 sum= 14805042797184
[ 2.781 ms] k= 4000 sum= 46781822900688
[ 3.539 ms] k= 5000 sum= 114218125116052
[ 4.756 ms] k= 6000 sum= 236808736848248
[ 5.223 ms] k= 7000 sum= 438721136165016
[ 6.806 ms] k= 8000 sum= 748454504589824
[ 7.645 ms] k= 9000 sum= 1198740116138576
[ 8.424 ms] k= 10000 sum= 1827127167830060
[ 9.303 ms] k= 11000 sum= 2675130127257140
[ 10.292 ms] k= 12000 sum= 3788610508835184
[ 10.220 ms] k= 13000 sum= 5218119174379260
[ 10.736 ms] k= 14000 sum= 7019284675919704
[ 10.782 ms] k= 15000 sum= 9249622447024312
[ 13.937 ms] k= 16000 sum= 11973761092807672
[ 14.610 ms] k= 17000 sum= 15260078673441888
[ 14.535 ms] k= 18000 sum= 19179420697925096
[ 15.512 ms] k= 19000 sum= 23809411309067844
[ 15.049 ms] k= 20000 sum= 29232792766430776
[ 15.454 ms] k= 21000 sum= 35530729593528460
[ 19.366 ms] k= 22000 sum= 42798909693505916
[ 19.164 ms] k= 23000 sum= 51128789507207824
[ 17.958 ms] k= 24000 sum= 60615343952225808
[ 18.378 ms] k= 25000 sum= 71367596207492300
[ 22.220 ms] k= 26000 sum= 83490183930172416
[ 22.565 ms] k= 27000 sum= 97093514169469316
[ 21.821 ms] k= 28000 sum= 112296054697946652
[ 24.109 ms] k= 29000 sum= 129222336308688284
[ 24.484 ms] k= 30000 sum= 147985909450776556
[ 23.518 ms] k= 31000 sum= 168726314083539724
[ 24.437 ms] k= 32000 sum= 191573248859171168
[ 25.810 ms] k= 33000 sum= 216665462512674040
[ 26.562 ms] k= 34000 sum= 244144733826449780
[ 25.961 ms] k= 35000 sum= 274165636445073084
[ 26.890 ms] k= 36000 sum= 306861019309280956
[ 27.347 ms] k= 37000 sum= 342403256303560068
[ 28.250 ms] k= 38000 sum= 380951178712974600
[ 28.792 ms] k= 39000 sum= 422654544640465536
[ 32.039 ms] k= 40000 sum= 467702202175553120
[ 31.689 ms] k= 41000 sum= 516261770711667188
[ 32.103 ms] k= 42000 sum= 568493102008765720
[ 33.605 ms] k= 43000 sum= 624601491354014924
[ 33.251 ms] k= 44000 sum= 684766511634347904
[ 38.647 ms] k= 45000 sum= 749168090843424836
[ 34.710 ms] k= 46000 sum= 818010181586572760
[ 36.381 ms] k= 47000 sum= 891505184775229460
[ 35.670 ms] k= 48000 sum= 969815208006099344
[ 36.745 ms] k= 49000 sum= 1053194632366715464
[ 39.265 ms] k= 50000 sum= 1141860626298697932
[ 41.430 ms] k= 51000 sum= 1235961937510193376
[ 39.108 ms] k= 52000 sum= 1335793856714706980
[ 39.395 ms] k= 53000 sum= 1441568696460268148
[ 41.918 ms] k= 54000 sum= 1553459252290960280
[ 40.703 ms] k= 55000 sum= 1671762162244218552
[ 41.705 ms] k= 56000 sum= 1796724219557144384
[ 43.305 ms] k= 57000 sum= 1928541735647080528
[ 49.717 ms] k= 58000 sum= 2067474716400847492
[ 43.599 ms] k= 59000 sum= 2213789303836196316
[ 48.271 ms] k= 60000 sum= 2367722439679998864
[ 45.474 ms] k= 61000 sum= 2529554127958058476
[ 47.711 ms] k= 62000 sum= 2699556160225194044
[ 50.947 ms] k= 63000 sum= 2877966575602455352
[ 53.505 ms] k= 64000 sum= 3065104550449828668
[ 54.559 ms] k= 65000 sum= 3261217251285430196
[ 53.066 ms] k= 66000 sum= 3466580213396622284
[ 51.004 ms] k= 67000 sum= 3681481683988726580
[ 52.176 ms] k= 68000 sum= 3906300655499965688
[ 52.597 ms] k= 69000 sum= 4141140842108345608
[ 54.037 ms] k= 70000 sum= 4386474829016834456
[ 55.015 ms] k= 71000 sum= 4642634007103668512
[ 56.036 ms] k= 72000 sum= 4909694650694395656
[ 56.753 ms] k= 73000 sum= 5188180625623422844
[ 56.944 ms] k= 74000 sum= 5478395966863778240
[ 58.519 ms] k= 75000 sum= 5780503390808063112
[ 58.851 ms] k= 76000 sum= 6095030347012208488
[ 59.481 ms] k= 77000 sum= 6422238822380824088
[ 59.821 ms] k= 78000 sum= 6762431127210826000
[ 60.474 ms] k= 79000 sum= 7115946997843513388
[ 62.483 ms] k= 80000 sum= 7483237599224918568
[ 62.773 ms] k= 81000 sum= 7864354728203024788
[ 63.597 ms] k= 82000 sum= 8259936085084243856
[ 63.737 ms] k= 83000 sum= 8670356746307209408
[ 65.268 ms] k= 84000 sum= 9095726603620478688
[ 66.408 ms] k= 85000 sum= 9536717580904610040
[ 66.726 ms] k= 86000 sum= 9993536125103095688
[ 67.575 ms] k= 87000 sum= 10466432130003173312
[ 68.633 ms] k= 88000 sum= 10956004885713459408
[ 68.506 ms] k= 89000 sum= 11462647299842391920
[ 69.760 ms] k= 90000 sum= 11986403043182154584
[ 70.185 ms] k= 91000 sum= 12528192303586301056
[ 71.192 ms] k= 92000 sum= 13088114114334229944
[ 72.118 ms] k= 93000 sum= 13666442859056921956
[ 72.514 ms] k= 94000 sum= 14263784093996812372
[ 73.450 ms] k= 95000 sum= 14880480246958258764
[ 75.154 ms] k= 96000 sum= 15516955556268238668
[ 75.907 ms] k= 97000 sum= 16173675941972720104
[ 76.416 ms] k= 98000 sum= 16851041998775635308
[ 76.931 ms] k= 99000 sum= 17549420431062508128
[ 77.511 ms] k=100000 sum= 18269345553999897648
这个解决方案是可行的,但不幸的是,当k很大时,它的速度实在太慢了(例如,k可以是一个与695335509116004一样大的数字)
var k=14;
var-res=0;
对于(设i=1;i首先简单优化:
如前所述lcm(i,j)
与lcm(j,i)
所以你可以计算两次几乎所有的和,相反,你可以只计算一次重复的和,然后将和的结果加倍
剩余非重复热lcm(i,j)
其中i==j
lcm(i,i)=i
因此它们形成了一个系列1+2+3+…+k
,可通过方程计算:k*(k+1)/2
使用SoE的素数分解2D LUT
之前的两种优化组合起来的速度略高于2倍(但是复杂性仍然是二次的,所以对于更大的数字来说,这仍然不够快
对于更高级、更快的方法,您需要足够的内存,以便可以执行基于SoE(埃拉托斯烯筛)的素数分解,从而大大加快GCD和LCM的运算速度(更大的复杂度和更小的恒定时间)其思想是让k
列表保存每个数的素数分解,直到k
然后,要获得GCD,您只需比较两个列表并将两个列表中的所有素数(及其幂)相乘即可
LCM类似,但几乎所有素数都要相乘,只需使用两个列表中存在的素数就可以了。这可以通过不使用列表中一个数字的素数分解而改为乘以该数字来进一步增强
两个列表的搜索都可以在O(m)
中完成,因为SoE将创建已经排序的列表,其中m
是分解i
或j
的素数,远小于它们的实际值
如果您想要预先分配单个i-th
列表,您可以将最多sqrt(i)
的素数作为上限。可以通过以下方法计算约10%的误差:
sqrt(i)/ln(sqrt(i));
所以我用这个来确保我有足够的:
ceil(1.2*sqrt(i)/ln(sqrt(i)))+1;
对于整数,您可以使用log2(或位数)代替+一些足够大的边距
然而,像这样的2D LUT对于bigk
!!!是大的,因为它不适合标准计算机的内存,所以对于bignumk
,这是不可能的
这种方法将给您带来更大的提升(测量结果显示,相对于小型k
上的#1+#2优化,运行时速度提高了约10倍,并且随着k
的增加而变得更好)。这种方法会影响复杂性(更好)在bigint上,但它依赖于bigint实现。我估计它在我的bigint上略低于二次,但没有尝试k
远未接近乘法阈值,因为这对于bigint来说仍然太慢
使用SoE为最多k
1D LUT的LUT加素数
这将加快GCD和LCM的运行速度,但速度不如前一个LUT。好的一面是,这需要更少的内存。但是,您当前的限制仍然需要约15.8 TB的存储空间,这在将来可能会实现。但是这仍然非常缓慢
使用PSLQ
这可能是最有希望快速完成此任务的方法。使用
k={ 1,2,3,... }
A(k) = sum_of_lcm_up_to(k)
A = 1,7,28,72,177,303,604,948,1497,...
这可能会让你得到更直接的方程
IIRC就是这样被发现的。直到那时,我们还不知道我们可以在不需要之前的数字的情况下计算Pi的各个数字,也不知道它可以在不使用大数算术的情况下计算出来
然而,我从来没有执行过PSLQ,也没有完全理解过PSLQ,因为它远离我的专业领域。我天真的理解是,它类似于对数字序列的各个数字进行PCA,试图找到序列迭代之间的数字关系
这里的C++代码结合了#1、#2、#3可以使用bigint编译,也可以不使用(如果不使用任何第三方libs),您只需使用您想要使用的任何东西重写bigint typedef。但是要注意32位无符号整数(没有bigint)这将溢出较小的数字,因此限制仅为k,这是一个较大的k
——二次时间不起作用。这里有一个O(k log log k)
——时间算法,与Eratosthenes的筛选相同
首先,一些数论。我们知道lcm(i,j)=(i*j)/gcd(i,j)
k k
sum sum (i*j),
i=1 j=1
然后我们可以用分配定律重写:
k k k 2
sum sum (i*j) = (sum i) = ((k+1)*k / 2)^2.
i=1 j=1 i=1
我们可以通过对可能的最大公约数求和来挽救这个想法:
k k k [k/g] 2
sum sum lcm(i, j) =? sum (1/g)*( sum (g*i) ),
i=1 j=1 g=1 i=1
但这当然是错误的,因为我们最终(例如,lcm(2,2)
被表示了两次,一次是g=1
,一次是g=2
。为了解决这个问题,我们转向Möbius反转,它给出了正确的公式
k k k [k/g] 2
sum sum lcm(i, j) = sum f(g)*(1/g)*( sum (g*i) ),
i=1 j=1 g=1 i=1
k 2
= sum g*f(g)*(([k/g]+1)*[k/g] / 2) ,
g=1
其中f(g)
的定义为
f(g) = product (1-p).
prime p|g
我们可以通过修改Eratosthenes的筛子对f
进行批量评估。Python 3如下:
def fast_method(k):
f = [1] * (k + 1)
for i in range(2, k + 1):
if f[i] != 1:
continue
for j in range(i, k + 1, i):
f[j] *= 1 - i
return sum(g * f[g] * ((k // g + 1) * (k // g) // 2) ** 2 for g in range(1, k + 1))
import math
def slow_method(k):
return sum(math.lcm(i, j) for i in range(1, k + 1) for j in range(k + 1))
def test():
for k in range(100):
assert fast_method(k) == slow_method(k), k
test()
一件小事情:“falsy”求值,如如果(!b)
比严格的布尔表达式,如b==0
需要更多的工作。因为它看起来像b
总是一个数字,你可能会通过这种方式获得一些性能。这回答了你的问题吗?lcm(i,j)
与lcm(j,i)是一样的
所以你做了太多重复的工作。你真的认为自己是695335509116004吗?你甚至找不到