【问题标题】:Why does this prime number algorithm work?为什么这个素数算法有效?
【发布时间】:2016-02-15 02:28:28
【问题描述】:
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    int anz;
    scanf("%d", &anz);
    time_t start = time(0);
    int *primZ = malloc(anz * sizeof(int));
    primZ[0] = 2;
    int Num = 0;

    for (int i = 1, num = 3; i < anz; num += 2) {
        for (int j = 1; j < i; j++) {
            if (num % primZ[j] == 0) {
                num += 2;
                j = 0;
            }

            //this part
            if (primZ[j] > i / 2)
                break;
        }

        primZ[i] = num;
        i++;
        printf("%d ,",num);
    }

    time_t delta = time(0) - start;
    printf("%d", delta);
    getchar();
    getchar();
    return 0;
}

代码运行良好,问题是为什么。 if(primZ[j] &gt; i/2) 部分使程序快 2 - 3 倍。它实际上应该是if(primZ[j] &gt; num/3),这很有意义,因为num 只能是奇数。但它是找到的素数的数量。对我来说完全是无稽之谈。请解释一下。

【问题讨论】:

  • 对于任意数n,如果m大于n/2,显然m i> 不能除 n.
  • @Jean-BaptisteYunès 是的,但i 不是正在测试的号码。它是迄今为止发现的素数总数的计数。换句话说,一个相当没有意义的数字。
  • 对错误感到抱歉。
  • 这个分支从来没有被使用过(只在开始时的琐碎案例),它看起来像是一些旧的优化尝试的剩余部分......
  • 这段代码也是错误的......它产生非素数。

标签: c primes


【解决方案1】:

您通过检查素数是否可被已找到的素数整除来检查素数是否为合数。但在这样做时,您只需检查并包括该数字的平方根,因为任何大于该数字除以该数字的数字都会留下一个小于该数字的平方根的数字。

例如 33 是​​合数,但您只需检查不超过 5 的数字即可意识到这一点,您无需检查它是否可被 11 整除,因为它留下了我们已经检查过的 3 (33/11=3) .

这意味着您可以通过以下方式改进您的算法

    for (int j = 1; j < i; j++) {
        if( primZ[j]*primZ[j] > num )
             break;

        if (num % primZ[j] == 0) {
            num += 2;
            j = 0;
        }
    }

i/2 的切割相比,您可以侥幸逃脱的原因是质数的分布。素数计数函数大约是i = num/log(num),然后你得到i/2 &gt; sqrt(num)

【讨论】:

    【解决方案2】:

    原因是实际的界限比num/3 更紧——你可以使用:

    if (primZ[j] > sqrt(num))
    

    那个的原因是,如果一个大于num 平方根的素数除以num,那么一定还有一个较低的素数可以除以(因为这种除法的结果必须小于平方根)。

    这意味着只要i/2 高于sqrt(num),代码就可以工作。所发生的情况是,低于某个数的素数的增长速度 超过该数的平方根,这意味着(完全意外地)i/2 是一个安全的使用范围。

    您可以查看您的 i 值如何表现 here - 他们称之为 pi(x),即小于 x 的素数。

    【讨论】:

      【解决方案3】:

      这是有道理的,因为如果 n 有两个因数,其中一个肯定小于或等于 n/2,感觉程序在 primZ 中找不到小于或等于 @987654323 的 i 的因数@ 这意味着没有 i 的因数——当然除了 1——。

      SenseprimZ按升序排列,j只增加,当primeZ[j] &gt; i/2表示primZ中没有小于i/2的i因子。

      P.S.开始搜索的点在 for 语句 num=3 的第一部分中说明,循环语句 num += 2 确保您只测试奇数

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-23
        • 2013-02-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多