繁体   English   中英

(相对)快速找到数字小于1000000的除数

[英](Relatively) Quickly find some divisor for a number < 10 000 000

假设我所说的一切都是关于自然数小于1000万的。

我正在为所有低于1000000的数字预先生成最低素数除数(LPD)的列表。例如,LPD(14)== 2,LPD(15)== 3,以及任何LPD素数本身。

我已经预先生成了所有素数。 访问第n个素数是一个简单的数组查找。 效率为:O(1)

我已经预先生成了一个查找表,用于确定给定数字是否为素数。 访问第n个素数是一个简单的数组查找。 效率为:O(1)

现在,我用于计算给定数字LPD的天真的算法是循环遍历所有素数,直到一个素数除以该数为止。 但这需要很长时间。 我可以在一半时间内找到所有数的最低除数的一半(少于1000万)生成质数(使用阿特金筛网,我不理解,但使用伪代码实现)。

有没有更好的算法来计算最低素数除数?

实际不确定为什么您会为同样的问题期望更高的性能。

筛分方法不是采用除法,而是采用每个质数,将其所有倍数标记为具有最低质数因子,除非已经标出。

int lpf[MAX] = {};
int primes[MAX_PRIME];

for(int i = 0; i < MAX_PRIME; ++i)
{
    int mult = primes[i];
    while(mult < MAX)
    {
       if (lpf[mult] == 0)
       {
            lpf[mult] = primes[i];
       }
       mult += primes[i];
    }
}

结尾处任何未标记的数字本身就是质数,因此此方法与在MAX下查找所有质数花费的时间相同。

根据@Keith的答案改编而成,新代码的运行速度更快(旧速度提高了13%!):

    public void SieveDivisors() {
        int iNum, iPrime, i6Prime; 
        _iaFirstDivisors = new int[_iLimit];
        _iaFirstDivisors[1] = 1;
        //Start at the largest primes, then work down. This way, we never need to check if the
        // lowest prime multiple is already found, we just overwrite it
        //Also, skip any multiples of 2 or 3, because setting those is a waste of time
        for (int iPrimeIndex = _iaPrimes.Length - 1; iPrimeIndex >= 1; iPrimeIndex--) {
            iPrime = _iaPrimes[iPrimeIndex];
            i6Prime = iPrime * 6;
            for (iNum = iPrime; iNum < _iLimit; iNum += i6Prime) {
                _iaFirstDivisors[iNum] = iPrime;
            }
            for (iNum = iPrime * 5; iNum < _iLimit; iNum += i6Prime) {
                _iaFirstDivisors[iNum] = iPrime;
            }
        }
        //Then record all multiples of 2 or 3
        for (iNum = 3; iNum < _iLimit; iNum += 6) {
            _iaFirstDivisors[iNum] = 3;
        }
        for (iNum = 2; iNum < _iLimit; iNum += 2) {
            _iaFirstDivisors[iNum] = 2;
        }
    }

您说您正在使用Atkin筛子生成素数列表。 如果您使用Eratosthenes筛网,则会自动获得LPD阵列-它只是用于筛网的阵列。 代替存储布尔跟踪的是使数字合成的第一个素数。

这是一些伪C代码:

int lpd[MAX] = {};
int primes[MAX_PRIMES];
int nprimes = 0;

void sieve() {
  for (int p = 2; p*p < MAX; ++p) {
    if (lpd[p] == 0) {
      primes[nprimes++] = p;
      lpd[p] = p;
      for (int q = p*p; q < MAX; q += p) {
        if (lpd[q] == 0) { lpd[q] = p; }
      }
    }
  }
}

最后,数组lpd[]将包含最低的素数除数,而primes[]将包含素数的列表。

暂无
暂无

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

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