1.首先最简单暴力的方法,那就是判断某数是否为质数时,就除以小于该数的所有数,若一个都不能被整除,则该数为质数,代码如下
void panduanzhishu(int m)
{
for (int i = 2; i < m; i++)
{
if (m % i == 0)
{
printf("不是质数");
return;
}
}
printf("是质数");
}
而下面代码是基于上面代码,求出基于4~m内所有的质数
int main()
{
int m = 0;
scanf("%d", &m);
for (int j = m; j > 4; j--)
{
int i = 2;
for (i = 2; i < j; i++)
{
if (j % i == 0)
{
break;
}
}
if (j == i)
{
printf("%d", j);
printf(" ");
}
}
return 0;
}
2.稍微复杂的求解质数的方法,运用的数学知识代码如下
#include <stdio.h>
#include <stdbool.h>
// 函数isPrime用于判断一个整数是否为质数,接受一个整数参数n,返回一个布尔值
bool isPrime(int n) {
// 如果n小于等于1,根据质数定义(质数大于1),不是质数,返回false
if (n <= 1) {
return false;
}
// 如果n小于等于3,2和3是质数,直接返回true
if (n <= 3) {
return true;
}
// 如果n能被2或者3整除,那它不是质数,返回false
if (n % 2 == 0 || n % 3 == 0) {
return false;
}
// 从5开始,每次加6进行判断,因为除了2和3之外的质数都可以表示为6k ± 1的形式(k为整数)
int i = 5;
while (i * i <= n) {
// 如果n能被i或者i + 2整除,说明n不是质数,返回false
if (n % i == 0 || n % (i + 2)==0) {
return false;
}
i += 6;
}
// 如果经过上述判断都没有返回false,说明n是质数,返回true
return true;
}
int main() {
int num;
// 提示用户输入一个整数
printf("请输入一个整数: ");
// 获取用户输入的整数
scanf("%d", &num);
// 调用isPrime函数判断num是否为质数,如果是则输出是质数,否则输出不是质数
if (isPrime(num)) {
printf("%d是质数\n", num);
} else {
printf("%d不是质数\n", num);
}
return 0;
}
int i = 5;
while (i * i <= n)
{
if (n % i == 0 || n % (i + 2)==0)
{
return false;
}
i += 6;
}
这一小段代码详细解释一下
- 代码段整体功能
- 这部分代码主要是用于进一步判断一个大于3的数
n
是否为质数。它基于一个数学规律:除了2和3之外的质数都可以表示为6k ± 1
(k
为整数)的形式。所以它通过循环检查n
能否被这些可能是质数的数整除。
- 这部分代码主要是用于进一步判断一个大于3的数
- 具体代码解释
int i = 5;
- 初始化一个变量
i
为5。这里选择5是因为前面已经单独处理了2和3的情况,而5是第一个符合6k - 1
(当k = 1
时)形式的数,用于开始后续的判断。
- 初始化一个变量
while (i * i <= n)
- 这个循环条件的意义是只要
i
的平方小于等于n
,就继续循环。这是因为如果一个数n
有大于sqrt(n)
(这里用i
来表示,当i * i<=n
时,i <= sqrt(n)
)的因数,那么它必然也有小于sqrt(n)
的对应因数。所以只需要检查到sqrt(n)
就可以判断n
是否为质数了。
- 这个循环条件的意义是只要
if (n % i == 0||n % (i + 2)==0)
- 这里检查
n
能否被i
或者i+2
整除。根据前面提到的规律,除了2和3之外的质数都可以表示为6k ± 1
的形式,所以i
代表6k - 1
形式的数,i + 2
代表6k+1
形式的数。如果n
能被这些数整除,那么n
就不是质数,所以返回false
。
- 这里检查
i += 6;
- 在每次循环后,将
i
增加6。这是因为下一个可能是质数的数(根据6k ± 1
的形式)需要通过增加6来得到。例如,当i = 5
时,下一个要检查的数是11
(5+6
),再下一个是17
(11 + 6
)等。
- 在每次循环后,将
这个循环条件的意义是只要i的平方小于等于n,就继续循环。这是因为如果一个数n有大于sqrt(n)(这里用i来表示,当i * i<=n时,i <= sqrt(n))的因数,那么它必然也有小于sqrt(n)的对应因数。所以只需要检查到sqrt(n)就可以判断n是否为质数了。 这里再用严谨的数学逻辑推导一下
- 假设存在大于nn的因数
- 设nn为一个正整数,假设nn有一个因数aa,且a>na>n。
- 因为aa是nn的因数,所以存在另一个因数bb,使得n=a×bn=a×b。
- 那么b=nab=an。
- 由于a>na>n,则b=na<nn=nb=an<nn=n。
- 结论
- 这就说明,如果nn有一个大于nn的因数aa,那么必然存在一个小于nn的因数bb。
- 在判断一个数nn是否为质数时,我们只需要检查到nn就足够了。因为如果在22到nn这个范围内没有找到nn的因数,那么大于nn的数也不可能是nn的因数(否则就会存在上述矛盾的情况)。所以在代码中通过i∗i⩽ni∗i⩽n(等价于i⩽ni⩽n)这个条件来限制循环范围,从而提高判断质数的效率。
除了2和3之外的质数都可以表示为6k ± 1的形式(k为整数) 这里再用严谨的数学逻辑推导一下
- 整数的余数分类
- 设nn为大于33的整数。当nn除以66时,根据余数定理,余数rr的取值范围是0⩽r<60⩽r<6,所以nn可以表示为n=6k+rn=6k+r,其中k∈Zk∈Z(整数集),r∈{0,1,2,3,4,5}r∈{0,1,2,3,4,5}。
- 分析各种余数情况
- 当r=0r=0时,n=6kn=6k,显然nn能被66整除,nn不是质数(因为n>3n>3)。
- 当r=2r=2时,n=6k+2=2(3k+1)n=6k+2=2(3k+1),能被22整除,不是质数(因为n>3n>3)。
- 当r=3r=3时,n=6k+3=3(2k+1)n=6k+3=3(2k+1),能被33整除,不是质数(因为n>3n>3)。
- 当r=4r=4时,n=6k+4=2(3k+2)n=6k+4=2(3k+2),能被22整除,不是质数(因为n>3n>3)。
- 剩余可能的质数形式
- 当r=1r=1时,n=6k+1n=6k+1。
- 当r=5r=5时,n=6k+5n=6k+5,而6k+5=6(k+1)−16k+5=6(k+1)−1,可以表示为6m−16m−1(令m=k+1m=k+1)。
- 结论
- 所以,除了22和33之外的质数(因为22、33是特殊情况,不满足这种形式)都可以表示为6k±16k±1的形式(k∈Zk∈Z)。
所以i代表6k - 1形式的数,i + 2代表6k+1形式的数。如果n能被这些数整除,那么n就不是质数,所以返回false。 这里再用严谨的数学逻辑推导一下
- 基于质数形式的假设
- 已知除了22和33之外的质数都可以表示为6k±16k±1(kk为整数)的形式。
- 我们设i=6k−1i=6k−1(kk为整数),那么i+2=(6k−1)+2=6k+1i+2=(6k−1)+2=6k+1。
- 分析整除性与质数的关系
- 对于一个数nn(n>3n>3),如果nn能被i=6k−1i=6k−1整除,即n=m×(6k−1)n=m×(6k−1)(mm为整数),那么nn除了11和nn本身外还有其他因数(6k−16k−1和mm),根据质数的定义,nn不是质数,所以返回falsefalse。
- 同理,如果nn能被i+2=6k+1i+2=6k+1整除,即n=p×(6k+1)n=p×(6k+1)(pp为整数),那么nn除了11和nn本身外还有其他因数(6k+16k+1和pp),nn不是质数,也应返回falsefalse。
- 结论
- 所以在判断一个数nn是否为质数的代码中,如果nn能被ii或者i+2i+2整除(ii代表6k−16k−1形式的数,i+2i+2代表6k+16k+1形式的数),那么nn就不是质数,所以返回falsefalse。