商城首页欢迎来到中国正版软件门户

您的位置:首页 >C++高效判断素数算法实现方法

C++高效判断素数算法实现方法

  发布于2026-03-02 阅读(0)

扫一扫,手机访问

sqrt(n) 是判断上限的关键,因为若n有大于sqrt(n)的因子d,则必存在对应小于sqrt(n)的因子n/d,故只需试除到sqrt(n)即可严格判定素数。

C++ 怎么判断素数 C++高效质数判断算法实现【数学】

为什么 sqrt(n) 是判断上限的关键

素数定义是大于1且只能被1和自身整除的正整数。暴力试除时,若 n 有大于 sqrt(n) 的因子 d,那必然存在对应的小于 sqrt(n) 的因子 n/d。所以只需检查到 sqrt(n) 即可——不是“大概可以”,而是数学上严格等价。

常见错误是写成 i <= sqrt(n) 放在循环条件里:每次迭代都调用 sqrt(浮点运算+类型转换),还可能因精度问题漏判或越界。正确做法是提前算一次整数上界:int limit = static_cast(std::sqrt(n)) + 1;,或更稳妥地用 i * i <= n 避开浮点。

  • i * i <= n 更快、无精度风险,但注意 i 别溢出(n 接近 INT_MAX 时,i 较大时 i*i 可能溢出;此时改用 long long i 或切回 sqrt
  • n == 2 要单独返回 true,否则 i=2i*i <= n 不成立,直接跳过循环误判为合数
  • 偶数只需检查 n == 2,其余偶数直接返回 false,省一半时间

is_prime 函数怎么处理边界和小数字

实际代码里最容易翻车的是 n <= 1n == 2n == 3 这几个点。C++ 没有内置素数判断,必须手动覆盖:

  • n < 2 → 直接 false(0、1、负数都不是素数)
  • n == 2true(唯一偶素数)
  • n % 2 == 0false(排除其余所有偶数)
  • n == 3 → 会被后续奇数循环捕获,但提前写 if (n == 3) return true; 并不必要,反而冗余

示例精简写法:

bool is_prime(int n) {
    if (n < 2) return false;
    if (n == 2) return true;
    if (n % 2 == 0) return false;
    for (int i = 3; i * i <= n; i += 2) {
        if (n % i == 0) return false;
    }
    return true;
}

需要批量判断时,别手写循环——用埃氏筛 sieve_of_eratosthenes

如果要判断 [2, N] 区间内所有数是否为素数(比如 N=1e6),单个 is_prime 调用 N 次是 O(N√N),而埃氏筛是 O(N log log N),快一个数量级以上。

核心逻辑是:从 2 开始,把每个素数的倍数全标为合数。关键细节:

  • 数组大小至少为 N+1,索引即数值(is_prime[i] 表示 i 是否为素数)
  • 外层循环只需到 sqrt(N),因为大于 √N 的素数,其最小未标记倍数必 > N
  • 内层标记从 i * i 开始,不是 2*i——因为更小的倍数(如 2*i, 3*i…)已被更小的素因子筛过了
  • vector 节省内存,但注意它特化实现可能慢;高频访问场景可用 vector

6k±1 优化真有必要吗

所有大于3的素数都形如 6k ± 1(因为其他形式:6k, 6k+2, 6k+3, 6k+4 都能被2或3整除)。利用这点可跳过更多合数,但实际收益有限:

  • 相比只试奇数(步长2),6k±1 把试除次数降到约 1/3,理论加速 ~1.5×
  • 但分支变多、循环逻辑复杂,现代 CPU 分支预测失败成本可能抵消收益
  • 对单次判断几乎没意义;仅当 n 极大(如 > 1e12)且调用频繁时才值得考虑,此时还要配合 Miller-Rabin
  • 日常使用坚持 i += 2 就够了,清晰、稳定、易调试

真正容易被忽略的是:int 溢出和 unsigned 类型混用。比如用 unsigned intn,再写 i * i <= n,当 i 接近 65536 时 i*i 会回绕,导致无限循环。统一用 long long i 或加溢出检查更稳妥。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注