简体   繁体   English

需要有关如何在JavaScript中分解非常大的数字的提示/建议

[英]Need a hint/advice as to how to factor very large numbers in JavaScript

My task is to produce an array containing all the prime numbers up to a 12-digit number. 我的任务是产生一个数组,其中包含所有最多为12位数字的质数。

I tried to emulate the Sieve of Eratosthenes by first making a function enumerate that produces an array containing every integer from 2 to num : 我试图通过首先使一个函数enumerate产生一个包含从2到num每个整数的数组来模仿Eratosthenes的筛网

var enumerate = function(num) {
    array = [];
    for (var i = 2; i <= num; i++) {
        array.push(i);
    }
    return array;
};

Then I made a function leaveOnlyPrimes which loops through and removes multiples of every array member up to 1/2 max from the array (this does not end up being every integer because the array become smaller with every iteration): 然后,我做了一个函数leaveOnlyPrimes ,它循环遍历并从数组中删除每个数组成员的倍数,最多不超过1/2 max (这不会成为每个整数,因为数组每次迭代都会变小):

var leaveOnlyPrimes = function(max,array) {
    for (var i = 0; array[i] <= max/2; i++) {
        (function(mult,array) {
            for (var i = mult*2; i <= array[array.length-1]; i += mult) {
                var index = array.indexOf(i);
                if (index !== -1) {
                    array.splice(index,1);
                }
            }
        })(array[i],array);   
    }
};

This works fine with numbers up to about 50000, but any higher than that and the browser seems to freeze up. 这个数字可以很好地工作,最大数字大约为50000,但是任何大于该数字的浏览器似乎都冻结了。

Is there some version of this approach which could be made to accommodate larger numbers, or am I barking up the wrong tree? 是否可以使用此方法的某些版本来容纳更大的数量,还是我在错误的树上吠叫?

up to 12 digits is 100,000,000,000. 最多12位数字是100,000,000,000。 That's a lot of primes (~ N/log N = 3,948,131,653). 这是很多素数(〜N / log N = 3,948,131,653)。

So, make a sieve up to 10^6, compress it into the array of ~78,500 core primes, and use them to sieve segment by segment all the way up to your target. 因此,制作一个最多10 ^ 6的筛子,将其压缩到约78,500个核心素数的阵列中,并使用它们逐段筛分直至目标。 Use primes up to the square root of the current upper limit of the segment. 使用素数直至段当前上限的平方根。 The size of the segment is usually chosen so that it fits into system cache. 通常选择段的大小,以使其适合系统缓存。 After sieving each segment, collect its primes. 筛分各段后,收集其质数。

This is known as segmented sieve of Eratosthenes. 这被称为Eratosthenes的分段筛。

As @WillNess suggests, you should not make a single monolithic sieve of that size. 作为@WillNess建议,你应该作出这样大小的单片筛。 Instead, use a segmented Sieve of Eratosthenes to perform the sieving in successive segments. 而是使用Eratosthenes的分段筛在连续段中进行筛分。 At the first segment, the smallest multiple of each sieving prime that is within the segment is calculated, then multiples of the sieving primes are marked composite in the normal way; 在第一个分段上,计算该分段内每个筛分质数的最小倍数,然后以常规方式将多个筛分质数标记为复合。 when all the sieving primes have been used, the remaining unmarked number in the segment are prime. 当使用所有筛选质数时,段中剩余的未标记数字为质数。 Then, for the next segment, the smallest multiple of each sieving prime is the multiple that ended the sieving in the prior segment, and so the sieving continues until finished. 然后,对于下一个片段,每个筛素数的最小倍数是在上一个片段中结束筛选的倍数,因此筛选继续进行直到完成。

Consider the example of sieving from 100 to 200 in segments of 20; 考虑在20个段中从100筛选到200的示例; the 5 sieving primes are 3, 5, 7, 11 and 13. In the first segment from 100 to 120, the bitarray has 10 slots, with slot 0 corresponding to 101, slot k corresponding to 100 + 2*k* + 1, and slot 9 corresponding to 119. The smallest multiple of 3 in the segment is 105, corresponding to slot 2; 这5个筛选质数分别为3、5、7、11和13。在从100到120的第一段中,位阵列具有10个插槽,插槽0对应于101,插槽k对应于100 + 2 * k * + 1,段中3的最小倍数是105,对应于插槽2;插槽9对应于119。 slots 2+3=5 and 5+3=8 are also multiples of 3. The smallest multiple of 5 is 105 at slot 2, and slot 2+5=7 is also a multiple of 5. The smallest multiple of 7 is 105 at slot 2, and slot 2+7=9 is also a multiple of 7. And so on. 插槽2 + 3 = 5和5 + 3 = 8也是3的倍数。插槽2处5的最小倍数是105,插槽2 + 5 = 7也是5的倍数。7的最小倍数是105在插槽2中,插槽2 + 7 = 9也是7的倍数。依此类推。

Function primes takes arguments lo , hi and delta ; 函数primes接受参数lohidelta ; lo and hi must be even, with lo < hi , and lo must be greater than the square root of hi . lohi必须是偶数,并且lo < hi ,并且lo必须大于hi的平方根。 The segment size is twice delta . 段大小是delta的两倍。 Array ps of length m contains the sieving primes less than the square root of hi , with 2 removed since even numbers are ignored, calculated by the normal Sieve of Eratosthenes. 长度为m的数组ps包含的筛选素数小于hi的平方根,并删除了2个,因为忽略了偶数,这是由Eratosthenes的常规筛计算得出的。 Array qs contains the offset into the sieve bitarray of the smallest multiple in the current segment of the corresponding sieving prime. 数组qs包含对应的筛选质数当前段中最小倍数的筛网位阵列的偏移量。 After each segment, lo advances by twice delta , so the number corresponding to an index i of the sieve bitarray is lo + 2 i + 1. 在每个段之后, lo前进两次delta ,因此与位数组的索引i对应的数字为lo + 2 i + 1。

function primes(lo, hi, delta)
  sieve := makeArray(0..delta-1)
  ps := tail(primes(sqrt(hi)))
  m := length(ps)
  qs := makeArray(0..m-1)
  for i from 0 to m-1
    qs[i] := (-1/2 * (lo + ps[i] + 1)) % ps[i]
  while lo < hi
    for i from 0 to delta-1
      sieve[i] := True
    for i from 0 to m-1
      for j from qs[i] to delta step ps[i]
        sieve[j] := False
      qs[i] := (qs[i] - delta) % ps[i]
    for i from 0 to delta-1
      t := lo + 2*i + 1
      if sieve[i] and t < hi
        output t
    lo := lo + 2*delta

For the sample given above, this is called as primes(100, 200, 10) . 对于上面给出的示例,这称为primes(100, 200, 10) In the example given above, qs is initially [2,2,2,10,8], corresponding to smallest multiples 105, 105, 105, 121 and 117, and is reset for the second segment to [1,2,6,0,11], corresponding to smallest multiples 123, 125, 133, 121 and 143. 在上面给出的示例中, qs最初为[2,2,2,10,8],对应于最小倍数105、105、105、121和117,并针对第二段重置为[1,2,6, [0,11],对应于最小倍数123、125、133、121和143。

The value of delta is critical; 增量的值至关重要。 you should make delta as large as possible so long at it fits in cache memory, for speed. 为了提高速度,您应该将增量尽可能地大,以便它可以容纳在高速缓存中。 Use your language's library for the bitarray, so that you only take a single bit for each sieve location. 对位数组使用语言的库,以便每个筛选位置仅占用一个位。 If you need a simple Sieve of Eratosthenes to calculate the sieving primes, this is my favorite: 如果您需要一个简单的Eratosthenes筛来计算筛分质数,这是我的最爱:

function primes(n)
  sieve := makeArray(2..n, True)
  for p from 2 to n step 1
    if sieve(p)
      output p
      for i from p * p to n step p
          sieve[i] := False

I'll leave it to you to translate to JavaScript. 我将它留给您翻译成JavaScript。 You can see more algorithms involving prime numbers at my blog . 您可以在我的博客上看到更多涉及素数的算法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM