【问题标题】:How can I make for loop with > 10^11 iterations faster?如何更快地进行 > 10^11 次迭代的 for 循环?
【发布时间】:2019-01-15 19:07:15
【问题描述】:

我正在尝试在 JS 中实现 2 个数学函数,但是我还需要调用 S(10**11) % 10**9,这需要很长时间。这些函数基于我拥有的 2 个数学函数: 我试着把它写到我的计算器(ti nspire)中,但是它没有足够的内存,这就是我写这个脚本的原因。

除了我已经完成的或可能解决求和之外,我真的不确定如何优化它,但我不确定如何使用 floor 函数来做到这一点。

function d(k){
    var a = 0;
    for(l=1;l<=k;l++){
        a += Math.floor(1/(1+k%l))*l;
    }
    return a;
}

function S(N){
    var a = 0;
    for(i=1;i<=N;i++){
        for(j=1;j<=N;j++){
            a += d(i*j);
        }
    }
    return a;
}

【问题讨论】:

  • 10**11 * 2 是一个非常大的数字,你不能只是暴力迭代。
  • d(2 * 3)d(3 * 2) 一样对吧?所以S 中的第二个总和只需转到i,然后将结果加倍。
  • 不确定这是否有帮助,但可以在 JS 中使用 GPU 加速数学,.. 看看这里 -> gpu.rocks
  • 这听起来像是一个典型的竞争性编程问题。如果是这种情况,那么您不应该尝试暴力解决方案。它几乎从不工作。您应该了解这个问题背后的逻辑(在这种情况下是数学)并找出如何大大简化它。即使这不是一个竞争性编程问题,也请查看d(k) 并尝试了解它的真正作用以及您是否可以更有效地在逻辑上计算相同的值。然后看看你是否可以更有效地计算d(i*j)(而不是仅仅d(x))。作为第一个提示:当Math.floor(1/(1+k%l)) 不是0
  • @SergGr 函数d(k) 返回k 的因子之和,是我为它创建的函数。查找因素总和的其他解决方案,我找到了this,但是我不确定如何实现它。 S(N) 是我得到的一个函数。

标签: javascript math calculus


【解决方案1】:

方程可以简化很多,使计算更容易。

首先,您需要存储 d(i) 的结果,这样您就无需重新计算它们。 从 d(i) 中找到 d(i+1) 很简单,只需使用即可

第二对循环可以简化很多。让我们考虑 S(5)

           i
       1     2     3     4     5
    1  d(1) d(2)  d(3)  d(4)   d(5)
    2  d(2) d(4)  d(6)  d(8)  d(10)
  j 3  d(3) d(6)  d(9)  d(12) d(15)
    4  d(4) d(8)  d(12) d(16) d(20)
    5  d(5) d(10) d(15) d(20) d(25)

我们可以看到有多少值被重新计算。首先注意矩阵如何关于对角线对称,节省一半。重新计算了许多其他值。

现在,如果我们看一下 d(k) 中的各个项。先看不同 k 和 i 的 mod(k,i) 的结果

        i
     123456789
     ---------
 1 | 0
 2 | 00
 3 | 010
k4 | 0010
 5 | 01210
 6 | 000210
 7 | 0113210
 8 | 00203210
 9 | 010143210

再次缓存值会有所帮助。除法是一个相对昂贵的操作,所以定义一个函数

f(m) = floor( 1 / ( 1 + m ) )

并在计算 d(k) 时将此函数与缓存结果一起使用。实际上让我们计算 f(m) 的值。现在 f(0) = floor(1/1) = 1。f(1) = floor(1/2) = 0 并且对于任何 m>1 f(m) = 0。

这极大地简化了计算。我们基本上只对 mod(k,i) = 0 的情况感兴趣。那是 k 是 i 的倍数的时候。

所以 d(k) 只是 k 的因子之和。

比起寻找 k 的因数,更容易查看 i 的倍数。

for(i=1;i<N;++i) {
    // find multiples of i
    for(j=1;j<???;++j) {
       m = i * j;
       d(m) += i;
    }
 }

现在我们得出d(k)是k的因子之和,我们可以简化S(N)的计算。

基本上对于给定的因子 m,我们想要找到 m 是 i*j 的因子的所有情况。

显然,1 是每个数字的因数,因此 1 出现 NN 次。 如果 i 或 j 是偶数,则 2 是一个因子。乘积 ij 是奇数 N/2 * N/2 次,所以偶数是 3/4 N*N 次。 (我假设 N 是偶数)

如果我们画乘法,则为 3

*  1  2  3  4  5  6
1        3        6
2        6       12
3  3  6  9 12 15 18
4       12       24
5       15       30
6  6 12 18 24 30 36

只需填写 3 的倍数。我们看到有 (1 - 2/3 * 2/3) N*N 倍数。

类似地,4 有 (1 - 3/4 * 3/4) N*N 倍数。

因此,如果我们考虑将倍数相加,整个事情就会变得容易得多。

【讨论】:

    猜你喜欢
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多