4

我正在尝试自学 node.js(没有 javascript 或真正的编程经验)并且在我试图解决的一个问题上遇到了障碍。我的目标是将前 100 个素数写入 txt 文件。以下是我到目前为止的代码。

var fs = require('fs');
var outfile = "test.txt";
var primality = function () {
    var arr = [];
    for (var n = 2; n <= 542; n++) {
        var primeTrue = true;
        for (var i = 2; i <= Math.sqrt(n); i++) {
            if (n % i === 0) {
                primeTrue = false;
            }
        }
        if (primeTrue) {
            arr.push(n);
        }
    }
    return arr;
}
fs.writeFileSync(outfile, arr);

我正在使用 codecademy javascript 实验室来测试我的循环和条件,这段代码似乎确实有效。(这也可能不是最好的方法,因为我必须将计数器设置为停止在 542,而不是让程序停止在第 100 个素数)。无论如何,当我添加

var outfile = "test.txt"

fs.writeFileSync(outfile, arr);

这并没有像我想象的那样将 100 个素数输出到 txt 文件中。我仍然处于学习的底层,因此非常感谢您提供的任何帮助。

先感谢您。

凯文

4

2 回答 2

12

你在一个功能中做了很多事情。如果将代码分解为两个函数,一个用于创建素数列表,另一个用于测试特定数字是否为素数,则代码可能更容易理解:

function listPrimes( nPrimes ) {
    var primes = [];
    for( var n = 2;  nPrimes > 0;  n++ ) {
        if( isPrime(n) ) {
            primes.push( n );
            --nPrimes;
        }
    }
    return primes;
}

function isPrime( n ) {
    var max = Math.sqrt(n);
    for( var i = 2;  i <= max;  i++ ) {
        if( n % i === 0 )
            return false;
    }
    return true;
}

现在您可以在 Node 中运行它:

var fs = require('fs');
fs.writeFileSync( 'test.txt', listPrimes(100) );

或直接在浏览器控制台中:

listPrimes( 100 );

(我没有在 Node 中测试代码,只在浏览器中测试。)

一些相关的注释:

  1. 计算sqrt()被移到 in 的循环之外isPrime(),因此不必为您正在测试的每个数字重新计算。
  2. nPrimes变量可让您生成所需的确切数量的素数,而无需542hack。

编写了这个简单的版本后,看看可能的优化是很有趣的。一种是只检查先前生成的素数的可分性,而不是检查直到平方根的所有整数。你可以这样做:

function listPrimes( nPrimes ) {
    var primes = [];
    for( var n = 2;  nPrimes > 0;  n++ ) {
        if( isPrime( n, primes ) ) {
            primes.push( n );
            --nPrimes;
        }
    }
    return primes;
}

function isPrime( n, primes ) {
    var max = Math.sqrt(n);
    for( var i = 0;  i < primes.length  &&  primes[i] <= max;  i++ ) {
        if( n % primes[i] === 0 )
            return false;
    }
    return true;
}

如果您要生成大量素数,这可能会更快,尽管对于其中的 100 个素数来说这并不重要,我倾向于坚持使用更简单的代码。

当然,如果你在谈论优化,总是值得考虑不同的算法。Eratosthenes的筛子很有趣,因为它快速、相当简单且易于理解。那篇维基百科文章很好地说明了它的工作原理。在 JavaScript 中,它可能看起来像这样:

function listPrimes( max ) {
    // Start with an empty list of primes
    var primes = [];
    // Initialize the sieve - each number is prime unless proven otherwise
    var sieve = new Array( max );
    for( var i = 1;  i <= max;  i++ ) {
        sieve[i] = true;
    }
    // Now check each number from 2 through max
    for( var p = 2;  p <= max;  p++ ) {
        if( sieve[p] ) {
            // p is prime, save it in the output list
            primes.push( p );
            // Mark p * 2, p * 3, p * 4, etc. as non-prime
            for( var t = p * 2;  t <= max;  t += p ) {
                sieve[t] = false;
            }
        }
    }
    return primes;
}

是的,在建议将代码拆分为两个函数之后,我现在又回到了一个函数。:-)

Sieve 的一个区别是你不能真的说,“请给我前 N 个素数”;相反,你问它,“请给我所有小于 N 的素数”。但是如果 N 是一个很大的数,它比其他方法快得多。

于 2013-06-29T18:24:02.973 回答
3

如果您预先初始化列表并跳过测试 2 的倍数的素数,这会更好

var primes = [2];
--nPrimes
for( var n = 3;  nPrimes > 0;  n += 2 )

我刚刚完成了启动工程课程作业@Coursera 的非常相似的代码;)

于 2013-06-29T21:10:35.540 回答