同一件事的两个功能,一个崩溃而另一个没有,为什么?

时间:2012-09-01 22:35:01

标签: javascript

我想要一个名为findFirst的函数,它接受参数n和q,并返回除以n大于或等于q的最小素数。所以首先我写了一个函数,可以说一个数字是否为素数。

var isPrime = function(n){
    if(n === 1){
        return false;
    }
    else if (n === 2 || n === 3){
        return true;
    }
    else {
        for(i=2; i < n; i++){
            if(i * i >= n){
            for(j=2; j<=i; j++){
                    if(n % j === 0){
                        return false;
                    }
                }
            return true;
            } 
        }
    }
};

可能有其他方法可以提高效率,但我很确定这个功能不是问题。

所以使用这个函数我第一次尝试编写findFirst:

var findFirst = function(n,q){
    var p = q;
        while(n % p !== 0 || isPrime(p) === false){
            p++;
        }
    return p;
};

此功能有效,但是大数字会崩溃,例如它在输入时崩溃(6310545154,3)。顺便说一句6310545154的主要功率分解是2 * 3155272577

所以我写了另一个函数,首先列出数字的素因子:

var getFactors = function(n){
    var factors = [];
    var k = n;
    var p = 2;
    while(isPrime(k) === false && k !== 1){
        while(k % p !== 0 || isPrime(p) === false){
            p = p+1;
        }
        while(k % p === 0){
            k = k/p;
        }
        factors.push(p);
    }
    if(isPrime(k) === true){
        factors.push(k);
        return factors;
    }
    if(k === 1){
        return factors; 
    }
};

现在我对findFirst的第二次尝试是:

var findFirst = function(n,q){
    var array = getFactors(n);
    var p = 0;
    for(i = 0; i < array.length; i++){
        if(array[i] >= q && p === 0){
            p = array[i];
        }
    }
    return p;
};

这个很棒。它不会在上面那么大的数字上崩溃并立即计算结果。谁能明白为什么会这样呢?看起来我原始尝试中的'while'循环与getFactors函数中的'while'循环非常相似。而第二次尝试看起来要复杂得多。

5 个答案:

答案 0 :(得分:3)

第二个程序返回非常快,因为你的数字只有一个大的素因子;一旦发现(全部)小的素数因子,它就会迅速退出循环。第一个程序在发现它是一个因素之前必须从3到3155272577一直计数。在2147483647之后,它必须从整数运算切换到浮点运算,这使得它更慢。

请注意

var isPrime = function(n) {
    ...
};

是一种创建函数的不寻常方式;通常你会写

function isPrime(n) {
    ...
}

答案 1 :(得分:0)

你在代码中有很多错误 - 例如,这种方式i是全局变量

for(i=2; i < n; i++){

你想做的是

for(var i=2; i < n; i++){

之后

factors[i] = k;

未定义i等等。

通过jslint或jshint运行代码,使其首先完全正确。

答案 2 :(得分:0)

您可以使用正则表达式快速检查素数。

function isPrimeNumber(n) {
    return !/^1?$|^(11+?)\1+$/.test((new Array(++n)).join('1'));
}

详细了解this post

编辑:虽然可能不适合大数字。更像是一个快速的解决方案。

答案 3 :(得分:0)

这并没有直接解决这个问题,但我认为重要的是要强调无响应的标签与崩溃不同。无响应只是意味着网页一直在执行JavaScript很久。

请记住,浏览器无法确定脚本是否会在不运行脚本的情况下完成 - 这称为暂停问题,,对于图灵完整的编程语言,它无法解决。浏览器杀死脚本的提议基于猜测,无论相关脚本是什么,都是如此。

答案 4 :(得分:0)

第二次尝试永远不会执行p = p+1;,实际上只会在while部分执行整个getFactors 2次:

   while(k % p !== 0 || isPrime(p) === false){
        p = p+1;
    }

不同于第一次尝试必须测试来自&#39; 3&#39;的每个p的数量。在第一次尝试中3155272577的素数和因子为n

    while(n % p !== 0 || isPrime(p) === false){
        p++;
    }

<强>为什么吗
第二次尝试以var p = 2;var k = n;开头,这意味着(k % p === 0)isPrime(p)都是true(当n=6310545154时)

while(isPrime(k) === false && k !== 1){
    while(k % p !== 0 || isPrime(p) === false){
        p = p+1;                                               /*  this is never executed for findFirst(6310545154, 3)  */
    }
    while(k % p === 0){
        k = k/p;
    }
    ...

然后k = k/p;立即将k缩减为3155272577,从而终止外部while(isPrime(k) === false ...

要在第二次尝试中观察相同的异常时间行为,请使用:
var factors = [2];var p = 3;

参考:Eratosthenes Sieve - Wikipedia