JavaScript中大量运行的Eratosthenes算法的筛选

JavaScript中大量运行的Eratosthenes算法的筛选,javascript,arrays,algorithm,primes,sieve-of-eratosthenes,Javascript,Arrays,Algorithm,Primes,Sieve Of Eratosthenes,我一直在尝试用JavaScript编写算法。基本上,我只是按照以下步骤进行操作: 创建从2到(n-1)的连续整数列表 让第一素数p等于2 从p开始,以p的增量进行计数,并删除每个数字(p和p的倍数) 转到列表中的下一个数字并重复2,3,4 将无意中删除的素数添加回列表 这就是我想到的: function eratosthenes(n){ var array = []; var tmpArray = []; // for containing unintentionally deleted ele

我一直在尝试用JavaScript编写算法。基本上,我只是按照以下步骤进行操作:

  • 创建从2到(n-1)的连续整数列表
  • 让第一素数p等于2
  • 从p开始,以p的增量进行计数,并删除每个数字(p和p的倍数)
  • 转到列表中的下一个数字并重复2,3,4
  • 将无意中删除的素数添加回列表
  • 这就是我想到的:

    function eratosthenes(n){
    var array = [];
    var tmpArray = []; // for containing unintentionally deleted elements like 2,3,5,7,...
    var maxPrimeFactor = 0;
    var upperLimit = Math.sqrt(n);
    var output = [];
    
    // Eratosthenes algorithm to find all primes under n
    
    // Make an array from 2 to (n - 1)
    //used as a base array to delete composite number from
    for(var i = 2; i < n; i++){
        array.push(i);
    }
    
    // Remove multiples of primes starting from 2, 3, 5,...
    for(var i = array[0]; i < upperLimit; i = array[0]){
        removeMultiples: 
        for(var j = i, k = i; j < n; j += i){
            var index = array.indexOf(j);
            if(index === -1)
                continue removeMultiples;
            else
                array.splice(index,1);
        }
        tmpArray.push(k);
    }
    array.unshift(tmpArray);
    return array;
    }
    
    函数eratosthenes(n){
    var数组=[];
    var tmpArray=[];//用于包含意外删除的元素,如2,3,5,7,。。。
    var maxPrimeFactor=0;
    var上限=数学sqrt(n);
    var输出=[];
    //求n下所有素数的Eratosthenes算法
    //制作一个从2到(n-1)的数组
    //用作从中删除复合编号的基数组
    对于(变量i=2;i
    它适用于小数字,但不适用于大于一百万的数字。我使用Node.js进行测试,整个过程似乎无穷无尽,没有显示内存错误。我读过一个解决方案(也是javascript),但仍然不能完全理解它


    问题:如何使这项工作适用于足够大的数字,如100万或以上?

    通过使用数组操作函数,如
    array#indexOf
    array#splice
    以线性时间运行,使Eratosthenes的筛选速度大大降低。当两个操作都有O(1)时

    以下是按照常规编程实践筛选埃拉托斯烯:

    var eratosthenes = function(n) {
        // Eratosthenes algorithm to find all primes under n
        var array = [], upperLimit = Math.sqrt(n), output = [];
    
        // Make an array from 2 to (n - 1)
        for (var i = 0; i < n; i++) {
            array.push(true);
        }
    
        // Remove multiples of primes starting from 2, 3, 5,...
        for (var i = 2; i <= upperLimit; i++) {
            if (array[i]) {
                for (var j = i * i; j < n; j += i) {
                    array[j] = false;
                }
            }
        }
    
        // All array[i] set to true are primes
        for (var i = 2; i < n; i++) {
            if(array[i]) {
                output.push(i);
            }
        }
    
        return output;
    };
    
    var-eratosthenes=函数(n){
    //求n下所有素数的Eratosthenes算法
    var数组=[],上限=Math.sqrt(n),输出=[];
    //制作一个从2到(n-1)的数组
    对于(变量i=0;i对于(var i=2;i这个问题在“大数”的定义上有点保守,并且承认它只从大约一百万开始,这是可行的;但是,它使用了相当多的内存,就像一个8字节的数字(64位的双实数)一样对于每个要筛选的元素,以及每个找到的素数的另一个8字节的数字,这个答案不适用于大约2.5亿或更大的“大数字”,因为它将超过JavaScript执行机器可用的内存量

    下面的JavaScript代码实现了Eratosthenes的“无限”(无界)页面分段筛选,克服了这个问题,因为它只使用一个位压缩的16 KB页面分段筛选缓冲区(一个位表示一个潜在的素数)并且只使用当前页面段中当前最大数的平方根以下的基本素数的存储,按顺序枚举实际找到的素数,而不需要任何存储;还可以通过仅筛选奇数组合来节省时间,因为唯一的偶数素数为2:

    var SoEPgClass = (function () {
      function SoEPgClass() {
        this.bi = -1; // constructor resets the enumeration to start...
      }
      SoEPgClass.prototype.next = function () {
        if (this.bi < 1) {
          if (this.bi < 0) {
            this.bi++;
            this.lowi = 0; // other initialization done here...
            this.bpa = [];
            return 2;
          } else { // bi must be zero:
            var nxt = 3 + 2 * this.lowi + 262144; //just beyond the current page
            this.buf = [];
            for (var i = 0; i < 2048; i++) this.buf.push(0); // faster initialization 16 KByte's:
            if (this.lowi <= 0) { // special culling for first page as no base primes yet:
              for (var i = 0, p = 3, sqr = 9; sqr < nxt; i++, p += 2, sqr = p * p)
                if ((this.buf[i >> 5] & (1 << (i & 31))) === 0)
                  for (var j = (sqr - 3) >> 1; j < 131072; j += p)
                    this.buf[j >> 5] |= 1 << (j & 31);
            } else { // other than the first "zeroth" page:
              if (!this.bpa.length) { // if this is the first page after the zero one:
                this.bps = new SoEPgClass(); // initialize separate base primes stream:
                this.bps.next(); // advance past the only even prime of 2
                this.bpa.push(this.bps.next()); // keep the next prime (3 in this case)
              }
              // get enough base primes for the page range...
              for (var p = this.bpa[this.bpa.length - 1], sqr = p * p; sqr < nxt;
                p = this.bps.next(), this.bpa.push(p), sqr = p * p);
              for (var i = 0; i < this.bpa.length; i++) { //for each base prime in the array
                var p = this.bpa[i];
                var s = (p * p - 3) >> 1; //compute the start index of the prime squared
                if (s >= this.lowi) // adjust start index based on page lower limit...
                  s -= this.lowi;
                else { //for the case where this isn't the first prime squared instance
                  var r = (this.lowi - s) % p;
                  s = (r != 0) ? p - r : 0;
                }
                //inner tight composite culling loop for given prime number across page
                for (var j = s; j < 131072; j += p) this.buf[j >> 5] |= 1 << (j & 31);
              }
            }
          }
        }
        //find next marker still with prime status
        while (this.bi < 131072 && this.buf[this.bi >> 5] & (1 << (this.bi & 31))) this.bi++;
        if (this.bi < 131072) // within buffer: output computed prime
          return 3 + ((this.lowi + this.bi++) * 2);
        else { // beyond buffer range: advance buffer
          this.bi = 0;
          this.lowi += 131072;
          return this.next(); // and recursively loop just once to make a new page buffer
        }
      };
      return SoEPgClass;
    })();
    
    var SoEPgClass=(函数(){
    函数SoEPgClass(){
    this.bi=-1;//构造函数重置枚举以启动。。。
    }
    SoEPgClass.prototype.next=函数(){
    如果(此值小于1){
    if(this.bi<0){
    这个.bi++;
    this.lowi=0;//其他初始化在此处完成。。。
    此参数为0.bpa=[];
    返回2;
    }否则{//bi必须为零:
    var nxt=3+2*this.lowi+262144;//刚好超出当前页面
    this.buf=[];
    对于(var i=0;i<2048;i++)this.buf.push(0);//更快的初始化16 KB字节:
    if(this.lowi>5]&(1>1;j<131072;j+=p)
    this.buf[j>>5]|=1>1;//计算素数平方的起始索引
    如果(s>=this.lowi)//根据页面下限调整开始索引。。。
    s-=this.lowi;
    else{//对于不是第一个素数平方实例的情况
    var r=(this.lowi-s)%p;
    s=(r!=0)?p-r:0;
    }
    //页面上给定素数的内部紧密复合消隐循环
    对于(var j=s;j<131072;j+=p)这个.buf[j>>5]|=1>5]&(1>0;//零缓冲区
    if(this.lowi>3]&(1>1;j<131072;j+=p)
    这个.buf[j>>3]|=1>>0;
    var s=(p*p-3)>>>1;//计算素数平方的起始索引
    如果(s>=this.lowi)//根据页面下限调整开始索引。。。
    s-=this.lowi;
    else{//对于不是第一个素数平方实例的情况
    var r=(this.lowi-s)%p;
    s=(r!=0)?p-r:0;
    }
    如果(p>0)>>3;j<16384;j+=p)这个.buf[j]|=msk;
    }
    }
    其他的
    //页面上给定素数的内部紧密复合消隐循环
    
    对于(var j=s;j<131072;j+=p)this.buf[j>>3]|=(1>>0)>3]&((1>>>0)仅仅为了好玩,我严格按照TDD的规则实现了Erastoten筛选算法(与节点一起运行)。这个版本应该足够面试了,作为一个学校练习,或者像我一样,只是为了混日子

    让我声明,我绝对认为公认的答案应该是GordonBGood提供的答案。

    module.exports.compute = function( size )
    {
        if ( !utils.isPositiveInteger( size ) )
        {
            throw new TypeError( "Input must be a positive integer" );
        }
    
        console.time('optimal');
        console.log();
        console.log( "Starting for optimal computation where size = " + size );
        let sieve = utils.generateArraySeq( 2, size );
    
        let prime = 2;
        while ( prime )
        {
            // mark multiples
            for ( let i = 0; i < sieve.length; i += prime )
            {
                if ( sieve[i] !== prime )
                {
                    sieve[i] = -1;
                }
            }
    
            let old_prime = prime;
            // find next prime number
            for ( let i = 0; i < sieve.length; i++ )
            {
                if ( ( sieve[i] !== -1 ) && ( sieve[i] > prime ) )
                {
                    prime = sieve[i];
                    break;
                }
            }
    
            if ( old_prime === prime )
            {
                break;
            }
        }
        console.timeEnd('optimal');
        // remove marked elements from the array
        return sieve.filter( 
            function( element )
            {
                return element !== -1;
            } );
    } // compute
    
    module.exports.compute=函数(大小)
    {
    如果(!utils.isPositiveInteger(大小))
    {
    抛出新类型错误(“输入必须是正整数”);
    }
    有限公司
    
    <!DOCTYPE html>
    
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Page Segmented Sieve of Eratosthenes in JavaScript</title>
        <script src="app.js"></script>
      </head>
      <body>
        <h1>Page Segmented Sieve of Eratosthenes in JavaScript.</h1>
    
        <div id="content"></div>
      </body>
    </html>
    
    "use strict";
    var SoEPgClass = (function () {
      function SoEPgClass() {
        this.bi = -1; // constructor resets the enumeration to start...
        this.buf = new Uint8Array(16384);
      }
      SoEPgClass.prototype.next = function () {
        if (this.bi < 1) {
          if (this.bi < 0) {
            this.bi++;
            this.lowi = 0; // other initialization done here...
            this.bpa = [];
            return 2;
          } else { // bi must be zero:
            var nxt = 3 + 2 * this.lowi + 262144; // just beyond the current page
            for (var i = 0; i < 16384; ++i) this.buf[i] = 0 >>> 0; // zero buffer
            if (this.lowi <= 0) { // special culling for first page as no base primes yet:
              for (var i = 0, p = 3, sqr = 9; sqr < nxt; ++i, p += 2, sqr = p * p)
                if ((this.buf[i >> 3] & (1 << (i & 7))) === 0)
                  for (var j = (sqr - 3) >> 1; j < 131072; j += p)
                    this.buf[j >> 3] |= 1 << (j & 7);
            } else { // other than the first "zeroth" page:
              if (!this.bpa.length) { // if this is the first page after the zero one:
                this.bps = new SoEPgClass(); // initialize separate base primes stream:
                this.bps.next(); // advance past the only even prime of 2
                this.bpa.push(this.bps.next()); // keep the next prime (3 in this case)
              }
              // get enough base primes for the page range...
              for (var p = this.bpa[this.bpa.length - 1], sqr = p * p; sqr < nxt;
                p = this.bps.next(), this.bpa.push(p), sqr = p * p);
              for (var i = 0; i < this.bpa.length; ++i) { // for each base prime in the array
                var p = this.bpa[i] >>> 0;
                var s = (p * p - 3) >>> 1; // compute the start index of the prime squared
                if (s >= this.lowi) // adjust start index based on page lower limit...
                  s -= this.lowi;
                else { // for the case where this isn't the first prime squared instance
                  var r = (this.lowi - s) % p;
                  s = (r != 0) ? p - r : 0;
                }
                if (p <= 8192) {
                  var slmt = Math.min(131072, s + (p << 3));
                  for (; s < slmt; s += p) {
                    var msk = (1 >>> 0) << (s & 7);
                    for (var j = s >>> 3; j < 16384; j += p) this.buf[j] |= msk;
                  }
                }
                else
                  // inner tight composite culling loop for given prime number across page
                  for (var j = s; j < 131072; j += p) this.buf[j >> 3] |= (1 >>> 0) << (j & 7);
              }
            }
          }
        }
        //find next marker still with prime status
        while (this.bi < 131072 && this.buf[this.bi >> 3] & ((1 >>> 0) << (this.bi & 7)))
          this.bi++;
        if (this.bi < 131072) // within buffer: output computed prime
          return 3 + ((this.lowi + this.bi++) << 1);
        else { // beyond buffer range: advance buffer
          this.bi = 0;
          this.lowi += 131072;
          return this.next(); // and recursively loop just once to make a new page buffer
        }
      };
      return SoEPgClass;
    })();
    
    module.exports.compute = function( size )
    {
        if ( !utils.isPositiveInteger( size ) )
        {
            throw new TypeError( "Input must be a positive integer" );
        }
    
        console.time('optimal');
        console.log();
        console.log( "Starting for optimal computation where size = " + size );
        let sieve = utils.generateArraySeq( 2, size );
    
        let prime = 2;
        while ( prime )
        {
            // mark multiples
            for ( let i = 0; i < sieve.length; i += prime )
            {
                if ( sieve[i] !== prime )
                {
                    sieve[i] = -1;
                }
            }
    
            let old_prime = prime;
            // find next prime number
            for ( let i = 0; i < sieve.length; i++ )
            {
                if ( ( sieve[i] !== -1 ) && ( sieve[i] > prime ) )
                {
                    prime = sieve[i];
                    break;
                }
            }
    
            if ( old_prime === prime )
            {
                break;
            }
        }
        console.timeEnd('optimal');
        // remove marked elements from the array
        return sieve.filter( 
            function( element )
            {
                return element !== -1;
            } );
    } // compute
    
    var eratosthenes = function(n) {
        // Eratosthenes algorithm to find all primes under n
        var array = [], upperLimit = Math.sqrt(n), output = [2];
    
        // Make an array from 2 to (n - 1)
        for (var i = 0; i < n; i++)
            array.push(1);
    
        // Remove multiples of primes starting from 2, 3, 5,...
        for (var i = 3; i <= upperLimit; i += 2) {
            if (array[i]) {
                for (var j = i * i; j < n; j += i*2)
                    array[j] = 0;
            }
        }
    
        // All array[i] set to 1 (true) are primes
        for (var i = 3; i < n; i += 2) {
            if(array[i]) {
                output.push(i);
            }
        }
    
        return output;
    };
    
    <!DOCTYPE html>
    <html>
    <title>Primes</title>
    <head>
    <script>
    function findPrimes() {
        var primes = []
        var search = []
    
        var maxNumber = 100
        for(var i=2; i<maxNumber; i++){
            if(search[i]==undefined){
                primes.push(i);
                for(var j=i+i; j<maxNumber; j+=i){
                    search[j] = 0;
                }
            }
        }
       document.write(primes);
    }
    findPrimes();
    </script>
    </head>
    <body>
    </body>
    </html>
    
    function sieveOfEratosthenes(num, fromSt = null) {
    let boolArr = Array(num + 1).fill(true); // Taking num+1 for simplicity
    boolArr[0] = false;
    boolArr[1] = false;
    
    for (
        let divisor = 2;
        divisor * divisor <= num;
        divisor = boolArr.indexOf(true, divisor + 1)
    )
        for (let j = 2 * divisor; j <= num; j += divisor) boolArr[j] = false;
    
    let primeArr = [];
    for (
        let idx = fromSt || boolArr.indexOf(true);
        idx !== -1;
        idx = boolArr.indexOf(true, idx + 1)
    )
        primeArr.push(idx);
    
    return primeArr;
    }