2016-08-29 95 views
2

所以我想这个伪代码从Wikipedia翻译成JavaScript:JavaScript中的Eratosthenes筛选器?

Input: an integer n > 1 

Let A be an array of Boolean values, indexed by integers 2 to n, 
initially all set to true. 

for i = 2, 3, 4, ..., not exceeding √n: 
    if A[i] is true: 
    for j = i^2, i^2+i, i^2+2i, i^2+3i, ..., not exceeding n : 
     A[j] := false 

Output: all i such that A[i] is true. 

这是据我得到:

function getPrimes(num) { 
    var a = []; 
    for (i=2;i<=num;i++){a.push(true);} 
    for (i=2;i<=Math.sqrt(num);i++){ 
    for (var j=i*i, coef=0, l=i;j<num-2;coef++){ 
     j = i*i+coef*l-2; 
     a[j]=false; 
    } 
    for (i=0;i<a.length;i++){ 
     if (a[i]){a.splice(i,1,i+2);} 
    } 
    } 
    return a; 
} 

getPrimes(10); // returns [2, 3, false, 5, false, 7, false, 9, false] 
       // 9 should be false 

因此,大家可以看到,该算法不捕获所有非素数。任何想法,我已经错过了?预先感谢任何想尝试它的人。

+0

你增加“我”在内环,所以外环只有当i = 2时才执行。一旦你的第二个内循环完成,我现在的大于sqrt(10)9. – Jecoms

+0

不要在每次迭代时重新计算'Math.sqrt(num)',这是一个昂贵的操作。 – Oriol

回答

2

您正在覆盖外循环的i变量,第二个内循环也使用i。所以外层循环只运行一次。

使用内部循环的另一个变量,如k,你会得到一个很好的结果。

但是没有必要让那个特定的内环定位在那里。它只需要在返回之前运行一次。所以你可以将它移出主循环。

一个小问题是,你的第一内环走得太远,因为j在循环的身体得到递增,并在j测试只有您已经指定了价值a[j]后会发生。 JavaScript只是创建那个元素,使阵列更长,但它会更好,如果你会阻止这种情况发生

我也会保留数组a的前2个索引代表数字0和1,只是为了让您的代码更具可读性:那么您不再需要那些+2-2

考虑到所有这些因素,再加上一些其他的优化,我建议这个ES6代码:

function getPrimes(num) { 
 
    var a = [...Array(num+1).keys()]; // =[0,1,...,num] 
 
    a[1] = 0; // 1 is not prime 
 
    var rt = Math.sqrt(num); // calculate only once 
 
    for (i=2;i<=rt;i++){ 
 
    for (var j=i*i; j<=num; j+=i) a[j]=0; 
 
    } 
 
    return a.filter(Number); // kick out the zeroes 
 
} 
 
// run it for 30 
 
var a = getPrimes(30); 
 
// Output 
 
console.log(a);

+0

我还没有见过array.filter()与以前的类型一起使用。它是一种黑客,它解析为函数(输入){返回输入==='数字'}的回调类型? – Jecoms

+0

'filter()'需要一个函数,你可以编写一个内联函数,比如'.filter(function(val){return Number(value);}'对'Number'的调用只会返回数字本身,但由于0是虚的,所以只保留非零值,所以是的,在这种情况下它只是一个虚拟函数 – trincot

+0

所以它基本上是隐式地调用Number构造函数,零将被视为falsy通过过滤函数去除 – Jecoms