判断一个数是否为素数的方法汇总

本文详细介绍了time命令的输出信息,特别是real、user和sys时间的区别,并通过实例讲解了用户态和核心态的概念。此外,还提供了三种不同的素数判断算法实现,包括基本方法、改进方法以及筛法。

time命令输出的信息

[1] real : 表示程序整个的运行耗时。可以理解为foo运行开始时刻你看了一下手表,程序运行结束时,你又看了一下手表,两次时间的差值就是本次real 代表的值
[2]user :这个时间代表的是foo运行在用户态的cpu时间,什么意思?
首先,我来讲一下用户态和核心态:
核心态(Kernel Mode):
在内核态,代码拥有完全的,不受任何限制的访问底层硬件的能力。可以执行任意的CPU指令,访问任意的内存地址。内核态通常情况下都是为那些最底层的,由操作系统提供的,可信可靠的代码来运行的。内核态的代码崩溃将是灾难性的,它会影响到整个系统。
—– In Kernel mode, the executing code has complete and unrestricted access to the underlying hardware. It can execute any CPU instruction and reference any memory address. Kernel mode is generally reserved for the lowest-level, most trusted functions of the operating system. Crashes in kernel mode are catastrophic; they will halt the entire PC.
用户态(User Mode):
在用户态,代码不具备直接访问硬件或者访问内存的能力,而必须借助操作系统提供的可靠的、底层的API来访问硬件或者内存。由于这种隔离带来的保护作用,用户态的代码崩溃(Crash),系统是可以恢复的。我们大多数的代码都是运行在用户态的。
—– In User mode, the executing code has no ability to directly access hardware or reference memory. Code running in user mode must delegate to system APIs to access hardware or memory. Due to the protection afforded by this sort of isolation, crashes in user mode are always recoverable. Most of the code running on your computer will execute in user mode.
为什么要区分Kernel Mode 和 User Mode呢?答案是隔离保护,使得系统更稳定。
好,讲完用户态和核心态之后,我们来看user time。我们已经说过了,这个指的是程序foo运行在用户态的cpu时间,cpu时间不是墙上的钟走过的时间,而是指CPU工作时间。
sys : 这个时间代表的是foo运行在核心态的cpu时间

1.根据素数的定义
即只能被1或者自身整除的自然数(不包括1),称为素数/质数。

#include<iostream>
using namespace std;

#define MAX 10000
bool IsPrime(int n)
{
    if(n == 1)
        return false;
    for(int i=2; i<n; ++i)
    {
        if(n%i == 0)
            return false;
    }
    return true;
}
int main(int argc, char const* argv[])
{
    int n = 0;
    while(n++ < MAX)
    {
        if(IsPrime(n))
            cout<<n<<'\t';
    }
    return 0;
}

统计耗时
这里写图片描述
2.利用定理
如果一个数是素数,那么它的最小质因数肯定<=它的开方.例如,50,最小质因数为2,2<50的开方。
不是合数,那就是素数。根据上面的定理,一个数只要能被比他的开方<=的所有数整除,那它肯定是合数;反之为素数。这样遍历的数量就会相应减少很多。

#include<iostream>
#include<math.h>
using namespace std;
#define MAX 10000
bool IsPrime(int n)
{
    int Sqtmp = sqrt(n);
    if(n == 1)
        return false;
    for(int i=2; i<=Sqtmp; ++i)
    {
        if(n%i == 0)
            return false;
    }
    return true;
}
int main(int argc, char const* argv[])
{
    int n = 0;
    while(n++ < MAX)
    {
        if(IsPrime(n))
            cout<<n<<'\t';
    }
    return 0;
}

统计耗时
这里写图片描述
3.筛法求质数。
这种方法高效,但内存消耗较大。
用筛法求素数的基本思想是:把从1开始的、某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。依次类推,直到筛子为空时结束。

<think>我们根据引用内容总结C语言判断素数的几种方法,并给出改进建议。 引用[1]:使用已知素数表来判断,但未给出具体实现。 引用[2]:使用循环从2到x-1,如果x能被其中任意一个整除则不是素数,否则是素数。但代码有漏洞:当x=1时,函没有返回值(因为循环条件n<x,当x=1时,循环不执行,然后执行if(x==n),但此时n为0,所以x!=n,因此函没有返回值)。另外,可以优化循环范围(只需到sqrt(x))。 引用[3]:判断101到200之间的整,用循环从2到i-1,统计能整除的的个。同样效率不高,且仅适用于101到200。 引用[4]:没有具体实现,但提到有试题汇总。 因此,我们综合给出几种常见方法,并优化: 1. 基础方法:从2到x-1逐个判断(改进:处理特殊值,如1不是素数,2是素数)。 2. 优化循环范围:实际上只需要判断到sqrt(x)(包含)即可,因为如果大于sqrt(x)的因子存在,必定对应一个小于sqrt(x)的因子。 3. 进一步优化:跳过偶(除了2以外偶都不是素数)。 下面给出几种实现: 方法1:基础方法(改进版) 注意:1不是素数,2是素数,小于1的都不是素数方法2:优化循环范围(到平方根) 注意:平方根可以用sqrt函,需要包含math.h。 方法3:跳过偶(先判断是否为2,如果是2则是素数;然后判断是否为偶,如果是偶(且不是2)则不是素数;接着从3开始每次加2,直到sqrt(x))。 我们分别实现: 方法1(基础改进): int isPrime(int x) { if (x < 2) return 0; // 小于2的不是素数 if (x == 2) return 1; // 2是素数 for (int i = 2; i < x; i++) { // 实际上这里可以优化,但为了展示基础方法 if (x % i == 0) return 0; } return 1; } 方法2(优化循环范围): #include <math.h> int isPrime(int x) { if (x < 2) return 0; if (x == 2) return 1; int limit = (int)sqrt(x) + 1; // 加1避免浮点误差,确保覆盖 for (int i = 2; i <= limit; i++) { if (x % i == 0) return 0; } return 1; } 方法3(跳过偶): int isPrime(int x) { if (x < 2) return 0; if (x == 2) return 1; if (x % 2 == 0) return 0; // 排除偶 int limit = (int)sqrt(x) + 1; for (int i = 3; i <= limit; i += 2) { // 从3开始,每次加2 if (x % i == 0) return 0; } return 1; } 注意:在方法2和方法3中,当x=2时,循环不会执行(因为limit=sqrt(2)+1≈1+1=2,循环条件i<=limit,但初始i=2,然后i=3>2所以不执行循环?不对,我们修正一下:对于x=2,我们在前面已经判断返回1,所以不会进入循环。对于x=3,limit=(int)sqrt(3)+1≈1+1=2,循环条件i=3>2,所以不会进入循环,返回1,正确。 但注意方法2中,当x=4时,limit= (int)sqrt(4)+1=2+1=3,循环中i=2时,4%2==0,返回0,正确。 然而,方法2中循环从2开始,包括2,所以能正确判断(除了2)都是合。但是当x=9时,limit=(int)sqrt(9)+1=3+1=4,循环i=2时9%2!=0,i=3时9%3==0,返回0,正确。 但是注意:在方法2中,如果x是2,我们已经在前面返回1,所以不会进入循环。对于x=3,循环从2到limit(即2),循环内i=2,3%2!=0,然后循环结束,返回1。 然而,在方法2中,循环条件i<=limit,当x=3时,limit= (int)sqrt(3)+1≈1+1=2,所以i从2开始,判断2<=2,进入循环,然后3%2!=0,然后i++变成3,判断3<=2?不成立,退出循环,返回1。所以正确。 但这里有一个小问题:sqrt函返回double,转换为int会截断,所以当x是一个完全平方时,比如9,sqrt(9)=3.0,那么limit=3+1=4?实际上只需要到3就可以了,因为3*3=9。所以我们可以写成i<=sqrt(x)或者i*i<=x,这样避免浮点运算。 因此,更高效且避免浮点方法是使用i*i<=x。 改进方法2(避免浮点): int isPrime(int x) { if (x < 2) return 0; if (x == 2) return 1; for (int i = 2; i * i <= x; i++) { if (x % i == 0) return 0; } return 1; } 同样,方法3也可以用这种方式改进: int isPrime(int x) { if (x < 2) return 0; if (x == 2) return 1; if (x % 2 == 0) return 0; for (int i = 3; i * i <= x; i += 2) { if (x % i == 0) return 0; } return 1; } 因此,我们推荐使用避免浮点的写法,因为浮点可能有精度问题和转换开销。 下面我们写出完整的程序(以第三种方法为例): </think>### C语言判断素数的实现方法 素数是指大于1且除了1和自身外没有其他正因子的自然。以下是几种常见的C语言实现方法,附详细说明: #### 方法1:基础循环法(推荐初学者) ```c #include <stdio.h> int is_prime(int n) { if (n <= 1) return 0; // 小于等于1的不是素数 for (int i = 2; i < n; i++) { if (n % i == 0) { return 0; // 能被整除则不是素数 } } return 1; // 是素数 } int main() { int num; printf("输入整: "); scanf("%d", &num); if (is_prime(num)) { printf("%d是素数\n", num); } else { printf("%d不是素数\n", num); } return 0; } ``` **特点**: - 时间复杂度:$O(n)$ - 直观易懂,适合教学场景 - 缺陷:对较大字效率较低[^2] #### 方法2:平方根优化法(推荐实践使用) ```c #include <stdio.h> #include <math.h> // 引入sqrt函 int is_prime(int n) { if (n <= 1) return 0; if (n == 2) return 1; // 2是素数 if (n % 2 == 0) return 0; // 排除偶 int limit = (int)sqrt(n) + 1; // 计算平方根边界 for (int i = 3; i <= limit; i += 2) { // 只检查奇因子 if (n % i == 0) return 0; } return 1; } ``` **优化点**: 1. **循环边界优化**:根据论原理,只需检查到$\sqrt{n}$即可 - 学原理:若$n$有因子$d$,则必有$d \leq \sqrt{n}$ 2. **偶排除**:大于2的偶都不是素数 3. **时间复杂度**:$O(\sqrt{n})$,性能显著提升[^3] #### 方法3:素数表法(适合重复判断) ```c int is_prime(int x, int knownPrimes[], int size) { if (x <= 1) return 0; for (int i = 0; i < size; i++) { if (x == knownPrimes[i]) return 1; if (x % knownPrimes[i] == 0) return 0; } // 此处可扩展添加新素数到表中 return 1; } ``` **适用场景**: - 需要多次判断不同字时 - 可预先存储小素数表加速判断 - 示例素数表:`{2, 3, 5, 7, 11, 13, 17, 19}`[^1] ### 关键知识点 1. **特殊值处理**: - 负、0、1都不是素数 - 2是唯一偶素数 2. **边界情况**: - 当输入极大值时(如$10^9$),方法2仍可在毫秒级完成 - 浮点精度问题:`sqrt(n)`需转换为整边界 3. **扩展优化**: - 使用6k±1定理进一步减少循环次 - 预生成素数表(埃拉托斯特尼筛法) - Miller-Rabin概率测试(适用于极大判定)
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值