【问题标题】:Is there any way to increase performance for this for loop in JS?有什么方法可以提高 JS 中这个 for 循环的性能吗?
【发布时间】:2015-11-21 14:16:09
【问题描述】:

我正在尝试解决项目欧拉 10 问题(找到所有低于 200 万的素数之和),但代码需要永远完成,我如何让它更快?

    console.log("Starting...")
var primes = [1000];
var x = 0;
var n = 0;
var i = 2;
var b = 0;
var sum = 0;

for (i; i < 2000000; i++) {
    x = 0;
    if (i === 2) {
            primes[b] = i
            sum += primes[b];
            console.log(primes[b]);
            b++;
        }
    for (n = i - 1; n > 1; n--) {
        if (i % n === 0) {
            x++;
        }
        if (n === 2 && x === 0) {
            primes[b] = i;
            sum += primes[b];
            console.log(primes[b]);
            b++;
        }

    }
}
console.log(sum)

【问题讨论】:

  • 您检测素数的方法效率低下。有一些优化:所有偶数都不是素数(使用i % 2 == 0 轻松检查)。你不需要从i - 1开始,你可以从Math.sqrt(i)开始,因为你只需要检查一半的潜在因素。
  • 你可以通过使用 web workers 来提高性能并给每个 worker 一个数字范围,你也可以通过只检查直到数字的 sqrt 来判断他是否可以让这个代码更快一点是否是素数
  • 这确实是 webworker 使用的完美有效示例。
  • 网络工作者很酷,但我真的希望人们不要开始使用它们在我的所有核心上传播低效代码

标签: javascript performance loops for-loop


【解决方案1】:

你可以做的最大的超级简单的事情来加快这个速度:

  • 找到除数后跳出内循环!

  • 检查素数时,从小除数开始,而不是大除数。您会发现合成的速度要快得多。

  • 您只需检查除数

  • 您只需要检查素数除数。你有他们的清单。

  • 在循环外处理 2,然后在循环内只做奇数:for(i=3;i&lt;2000000;i+=2)

【讨论】:

  • 谢谢你们,这真的很有帮助
【解决方案2】:

这是基于Sieve of Eratosthenes 的另一个版本。它需要更多的内存,但如果你不关心它,它也很快。

// just a helper to create integer arrays
function range(from, to) {
    var numbers = [];
    for (var i=from ; i<=to ; i++) {
        numbers.push(i);
    }
    return numbers;
}

function primesUpTo(limit) {
    if (limit < 2) return [];

    var sqrt = Math.floor(Math.sqrt(limit));
    var testPrimes = primesUpTo(sqrt);
    var numbers = range(sqrt+1, limit);
    testPrimes.forEach(function(p) {
        numbers = numbers.filter(function(x) { return x % p > 0 });
    });
    return testPrimes.concat(numbers); 
}

var primes = primesUpTo(2000000);
var sum = primes.reduce(function(acc, e) { return acc + e });

【讨论】:

    【解决方案3】:

    既然你保留了一个素数数组,你可以把这个过程分成两个步骤:

    • 生成素数,达到 200 万的限制
    • 和总结。

    正如其他人所指出的,您只需要检查一个候选数是否可以被另一个不大于该候选平方根的素数整除。如果您可以将一个数写为质数的乘积,那么其中一个质数将始终小于或等于该数的平方根。

    此代码可以进一步优化,但比您的初始版本快几个数量级:

    function primesUpTo(limit) {
        if (limit < 2) return [];
    
        var sqrt = Math.floor(Math.sqrt(limit));
        var testPrimes = primesUpTo(sqrt);
        var result = [].concat(testPrimes);
    
        for (var i=sqrt+1 ; i<=limit ; i++) {
            if (testPrimes.every(function(x) { return (i % x) > 0 })) {
                result.push(i);
            }
        }
        return result;
    
    }
    
    var primes = primesUpTo(2000000);
    var sum = primes.reduce(function(acc, e) { return acc + e });
    

    【讨论】:

      猜你喜欢
      • 2012-02-11
      • 1970-01-01
      • 1970-01-01
      • 2020-12-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-09
      • 2017-12-01
      • 1970-01-01
      相关资源
      最近更新 更多