javascript - 如何更快地进行 > 10^11 次迭代的 for 循环?
问题描述
我正在尝试在 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;
}
解决方案
方程可以简化很多,以使计算更容易。
首先,您需要存储 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 出现 N N 次。如果 i 或 j 是偶数,则 2 是一个因子。乘积 i j 是奇数 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 倍数。
因此,如果我们考虑将倍数相加,整个事情就会变得容易得多。
推荐阅读
- ios-simulator - 如何使用 libtool 为 iOS 模拟器创建一个 dylib?
- typescript - 说服 typescript 对象具有来自 Object.entries/Object.keys 的键
- javascript - React - 在作为道具传递的点击处理程序中传递组件道具
- python - 如何在不创建新列表的情况下修改列表中的每个元素
- ruby-on-rails - 使用带有导轨的黄瓜进行自动化测试时出错
- mongodb - MongoDB / Discord.js - 检查集合的存在
- excel - 区分大小写的 minif?
- chatbot - 为什么没有检测到我的通配符 + think + 条件?
- reactjs - 将 Formik 与 React.FC 一起使用
- c++ - 对 ofstream 的访问冲突