sqrt里的参数需要注意类型否则编译错误
#include <iostream>
#include <stdio.h>#include <cmath>
using namespace std;
int isPrime(int m)
{
for(int i = 2;i <= sqrt((double)m);i++)
{
if(m % i == 0)
return 0;
}
return 1;
}
int main()
{
int n;
while(scanf("%d",&n) == 1 && n != 0)
{
int a,flag = 0;
for(a = 3;a <= n / 2;a += 2)
{
if(isPrime(n - a) && isPrime(a))
{
flag = 1;
printf("%d = %d + %d\n",n,a,n - a);
break;
}
}
if(!flag)
printf("Goldbach's conjecture is wrong.\n");
}
return 0;
}
//筛法的自己实现
int num[1000000];
//0素1合
void getPrime()
{
memset(num,0,sizeof(num));
num[0] = 1;
num[1] = 1;
for(int i = 2;i < 1000000;i++)
{
int tmp;
if(!num[i])
{
tmp = i + i;
while(tmp < 1000000)
{
num[tmp] = 1;
tmp += i;
}
}
}
}
int isPrime(int m)
{
return num[m] == 0;
}
//思路:此题要求输入一个大于4的数, 输出表述成两个素数的和,我用 scanf 和 printf。
//提交情况: Compile Error了几次,主要是用j = sqrt(num)时选了C++编译器,用GCC一次就AC
//收获:学到了判断素数的基本用法
//经验: 写好代码后本地编译而且需要静态观察,杜绝编译错误。
// 求出所有素数的方法
思路:以空间换时间,利用筛选法求素数。 4076K 157MS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
1倍不算
遍历一遍,“删掉”(标记)2的倍数:得2 3 5 7 9 11 13 15 17 19 21 23 25 (4,6,8的倍数就是2的倍数)
遍历一遍,删掉3的倍数:得2 3 5 7 11 13 17 19 23 25(6, 9, 12的倍数就是3的倍数)
遍历一遍,删掉5的倍数:得2 3 5 7 11 13 17 19 23(10, 15, 25的倍数就是5的倍数)
为了减小判断,加入if判断
#define MAX 1000001
int prime[MAX] = { 0}; // 0为素数,1不是素数
void getprime()
{
int i, j;
for (i = 2; i < MAX/ 2; i++)
{
if (!prime[i]) // 加上判断减少时间
{
for (j = 2; i*j < MAX; j++)
{
prime[j*i] = 1; // 是某一个数的倍数
}
}
}
prime[ 0] = prime[ 1] = 1;
}
int main()
{
int n, i, has;
getprime();
has = 0;
while (scanf( "%d", &n)== 1 && n != 0) {
for (i = 3; i <= n/ 2; i += 2) { // 只有奇数才可能是素数
if (prime[i] == 1 || prime[n-i] == 1)
{
continue;
} else {
printf( "%d = %d + %d \n ", n, i, n-i);
break;
}
}
if (i > n/ 2)
printf( "Goldbach's conjecture is wrong. \n ");
}
return 0;
}
// AC Co
1 |
#include <stdio.h> |
另附判断素数的方法:
判断n是否为素数
1、最简单的方法
用n除以2-sqrt(n),有一个能除尽就不是素数,否则是素数。
时间复杂度:O(sqrt(n))
2、素数判断法:
这种方法是对上面方法的改进,上面方法是对2-sqrt(n)之间的数进行判断是否能除尽,而因为有如下算术基本定理,可以减少判断量。
算术基本定理:又称为素数的唯一分解定理,即:每个大于1的自然数均可写为素数的积,而且这些素因子按大小排列之后,写法仅有一种方式。例如:6936 = 2^3×3×17^2,1200 = 2^4×3×5^2。
由算术基本定理知,任何合数都可分解为一些素数的乘积,所以判断一个数能不能被2-sqrt(n)之间的素数整除即可。但是必须知道2-sqrt(n)之间的所有素数。
3、筛选法
这种方法可以找出一定范围内的所有的素数。
思路是,要求10000以内的所有素数,把1-10000这些数都列出来,1不是素数,划掉;2是素数,所有2的倍数都不是素数,划掉;取出下一个幸存的数,划掉它的所有倍数;直到所有幸存的数的倍数都被坏掉为止。
要找出10000以为的所有的素数,则需要一个大小为10000的数组,将其所有元素设置为未标记
首先把1设置为标记,从2开始,标记所有是它倍数的数,然后对下一个没有标记的数进行标记它的倍数。
当标记完成后,所有未标记的数即为素数。
这种算法需要O(n)的空间,不要偶数,可以节省一半的存储空间,标记需要O(n^2/logn)(我写的,不知道对不对),判断是否是素数只需要O(1)的时间。
贴一下程序代码:
/*
2009.5.12 by HK
*/
#include <stdio.h>
#include <math.h>
#include <string.h>
int a [ 10000 ];
//100以内的素数
int prime100 [] =
{
2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 , 31 , 37 , 41 , 43 , 47 , 53 , 59 , 61 , 67 , 71 , 73 , 79 , 83 , 89 , 97 ,
};
/************************************************************************/
/* 第一种方法:最简单的方法 */
/************************************************************************/
int is_prime1( int n)
{
if(n % 2 == 0)
return 0;
for( int i = 3; i <= sqrt(( double)n); i += 2)
if(n % i == 0)
return 0;
return 1;
}
/************************************************************************/
/* 第二种方法:素数判断法 */
/* 若判断10000以内的数,需要知道100以内的所有素数 */
/************************************************************************/
int is_prime2( int n)
{
int i;
for( i = 0; i < 25; i ++)
if(n % prime100 [ i ] == 0)
return 0;
return 1;
}
/************************************************************************/
/* 第三种方法:筛选法,打素数表,然后判断 */
/************************************************************************/
//筛选,a[i]=0,i为素数
void create_table()
{
int i , tmp;
memset( a , 0 , sizeof( a));
a [ 0 ] = 1;
a [ 1 ] = 1;
for( i = 2; i < 10000; i ++)
{
if( ! a [ i ])
{
tmp = i * 2;;
while( tmp < 10000)
{
a [ tmp ] = 1;
tmp += i;
}
}
}
}
int is_prime3( int n)
{
return ! a [n ];
}
int main()
{
int num , res;
create_table();
printf( "Input the num:");
scanf( "%d" , & num);
res = is_prime3( num);
if( res)
printf( "%d is a prime \n " , num);
else
printf( "%d is not a prime \n " , num);
return 0;
}
判断素数的四种方法
/*求素数的三种方法
一:for(i=2;i<=(n-1);i++)
if(n%i==0)i在2到n-1之间任取一个数,如果n能被整除则不是素数,否则就是素数
二:for(i=2;i<n/2;i++)
if(n%i==0) /*i在2到n/2之间任取一个数,如果n能被整除则不是素数,否则就是素数
三:for(i=2;i<(n=sqrt(n));i++)
if(n%i==0) /*i在2到sqrt(n)之间任取一个数,如果n能被整除则不是素数,否则就是素数,
四、追求速度的一种方法(用素数表)
算术基本定理(素数唯一分解定理):任何一大于1的整数均可以分解为素数的乘积,若不考虑素数乘积的先后顺序,则分解式是唯一的。换句话说, 任意正整数n可以写成n=2a1*3a2*5a3*…,其中a1,a2,a3等为非负整数。
新方法的思路其实不新,只是利用了一个小技巧:一个正整数如果不能被所有不大于它的平方根的素数整除,则它一定是素数。我在判断正整数i是否为素数时,不是让它去整除每一个不大于它的平方根的正整数,而是让它去整除已经得到的素数表中的素数(此时素数表中的素数比i要小的多),这样就大大地减少了运算量。
如果需要求超大的素数,int64 的有20位,甚至高精度情况下的素数,百位上千位可以建立素数表来求 ,所以,对于每个我们需要判断的数,只需要用素数表里的数来除即可,若都不能整除,那此数一定也是素数,那就把它加入素数表内,一直求下去就行,一般来说 10000个数的素数表就能判断int32内的素数,素数表能判断素数的范围是表内最大那个素数的平方。
证明:for j=2 to 表内最大的那个素数(通常这里写sqrt(x)),所以最大可以算到表内最大的那个素数的平方。
【转载】几种常见的素数判断算法te>收藏te>
求解一个算法,我们首先要知道它的数学含义.依据这个原则,首先我们要知道什么是素数.; 素数是这样的整数,它除了表示为它自己和1的乘积以外,无论他表示为任何两个整数的乘积。
找素数的方法多种多样。
1:是从2开始用“是则留下,不是则去掉”的方法把所有的数列出来(一直列到你不想再往下列为止,比方说,一直列到10,000)。第一个数是2, 它是一个素数,所以应当把它留下来,然后继续往下数,每隔一个数删去一个数,这样就能把所有能被2整除、因而不是素数的数都去掉。在留下的最小的数当中, 排在2后面的是3,这是第二个素数,因此应该把它留下,然后从它开始往后数,每隔两个数删去一个,这样就能把所有能被3整除的数全都去掉。下一个未去掉的 数是5,然后往后每隔4个数删去一个,以除去所有能被5整除的数。再下一个数是7,往后每隔6个数删去一个;再下一个数是11,往后每隔10个数删一个; 再下一个是13,往后每隔12个数删一个。就这样依法做下去。
但是编程我们一般不采用上面的方法,并不说这中方法计算机实现不了,或者说实现算法比较复杂。因为它更像一个数学推理。最后我们也给一个算法。
下面我们介绍几种长用的编程方法。
2:遍历2以上N的平方根以下的每一个整数,是不是能整除N;(这是最基本的方法)
3:遍历2以上N的平方根以下的每一个素数,是不是能整除N;(这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道)
4:采用Rabin-Miller算法进行验算;
例如:N=2^127-1是一个38位数,要验证它是否为素数,用上面几个不同的方法:
验算结果,假设计算机能每秒钟计算1亿次除法,那么
算法2要用4136年,算法3要用93年,算法4只要不到1秒钟!(这些数据是通过计算得到)
另外印度有人宣称素数测试是P问题,我一直没有找到那篇论文,听说里面有很多数学理论。如果那位大人有这篇论文,麻烦转发一份。
下面我们分别实现上面的三种算法:
以下算法我们不涉及内存溢出,以及大数字的问题。如果测试数字超过2^32,发生内存溢出,你需要自己使用策略解决这个问题,在这里只讨论32位机有效数字算法。
1:// 算法0:是从2开始用“是则留下,不是则去掉”的方法把所有的数列出来
// 最后数组中不为0的数字就是要查找的素数。
void PrimeNumber0()
{
// int time ::GetTickCount();
// cout << "start time:" << time << endl;
int Max[MAX_NUMBER]; // 在栈上分配,栈上空间要求一般都在2M之间,
// 如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).
memset(Max,0,MAX_NUMBER);
for(int i = 0 ; i < MAX_NUMBER; ++i)
{
Max[i] = i;
}
int cout = 0;// 记录当前i的位置
// 遍历整个数组
for(i = 1; i < MAX_NUMBER; ++i)
{
if(Max[i] != 0 )// 如果数据不为0,说明是一个素数
{
int iCout = i;
int j = Max[i];// 记录数组中数组位的数字,以便设置
while((iCout+=j) < MAX_NUMBER)
{
// 把不是素数的数位在数组中置为0
Max[iCout] = 0;
}
++cout;
}
}
// int time ::GetTickCount();
// cout << "end time:" << time << endl;
}
2:这个算法可以修改成为,验证一个给定数字是否是一个素数。
// 因为我们讨论多个算法,所以我们把每个算法都单独
// 写在一个或多个函数内。这些函数并不要求输入值和返回值
// 如果你需要这些结果,可以自己修改。
// 算法1:遍历2以上N的平方根以下的每一个整数,是不是能整除N;
void PrimeNumber1()
{
// int time ::GetTickCount();
// cout << "start time:" << time << endl;
int Max[MAX_NUMBER/2]; // 在栈上分配,栈上空间要求一般都在2M之间,
// 如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少
// 所以没有必要申请和所求数字同样大小的空间。
memset(Max,0,MAX_NUMBER);
Max[0] = 2;// 放入第一个素数,有人说2不是素数,如果你是其中一员,就改成3吧
int cout = 1;// 记录素数个数
// 挨个数进行验证
bool bflag = true;
for(int i = 3; i < MAX_NUMBER; ++i)
{
bflag = true;
// 需要是使用数学库(math.h)中sqrt
int iTemp = (int)sqrt((float)i);// 强制转换成int类型,有的人在这里使用i+1就是为了增加sqrt的精度
// 没有特殊函数,你也可以使用int iTemp = (int)sqrt(i)+1;来提高进度
for (int j = 2; j < iTemp; ++j)
{
if(i%j == 0)// 求余,如果为0说明,可以整除,不是素数。
{
bflag = false;
break;
}
}
// 经过验证是素数,放入数组。
if(bflag)
{
Max[cout++] = i;
}
}
// int time ::GetTickCount();
// cout << "end time:" << time << endl;
}
3:这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道
// 算法2:遍历2以上N的平方根以下的每一个素数,是不是能整除N;
// (这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道)
void PrimeNumber2()
{
// int time ::GetTickCount();
// cout << "start time:" << time << endl;
int Max[MAX_NUMBER/2]; // 在栈上分配,栈上空间要求一般都在2M之间,
// 如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少
// 所以没有必要申请和所求数字同样大小的空间。
memset(Max,0,MAX_NUMBER);
Max[0] = 2;// 放入第一个素数,有人说2不是素数,如果你是其中一员,就改成3吧
int cout = 1;// 记录素数个数
// 挨个数进行验证
bool bflag = true;
for(int i = 3; i < MAX_NUMBER; ++i)
{
bflag = true;
// 需要是使用数学库(math.h)中sqrt
int iTemp = (int)sqrt((float)i);// 强制转换成int类型,有的人在这里使用i+1就是为了增加sqrt的精度
// 没有特殊函数,你也可以使用int iTemp = (int)sqrt(i)+1;来提高进度
/
// 修改的是这里以下的部分
for (int j = 0; j < cout; ++j)
{
if(i%Max[j] == 0)// 求余,如果为0说明,可以整除,不是素数。
{
bflag = false;
break;
}
}
// 修改的是这里以上的部分
//
// 经过验证是素数,放入数组。
if(bflag)
{
Max[cout++] = i;
}
}
// int time ::GetTickCount();
// cout << "end time:" << time << endl;
}
4:采用Rabin-Miller算法进行验算,Rabin-Miller算法是典型的验证一个数字是否为素数的方法。判断素数的方法是 Rabin-Miller概率测试,那么他具体的流程是什么呢。假设我们要判断n是不是素数,首先我们必须保证n 是个奇数,那么我们就可以把n 表示为 n = (2^r)*s+1,注意s 也必须是一个奇数。然后我们就要选择一个随机的整数a (1<=a<=n-1),接下来我们就是要判断 a^s=1 (mod n) 或a^((2^j)*s)= -1(mod n)(0<=j如果任意一式成立,我们就说n通过了测试,但是有可能不是素数也能通过测试。所以我们通常要做多次这样的测试,以确保我们得到的是一 个素数。(DDS的标准是要经过50次测试)
// 算法3:采用Rabin-Miller算法进行验算
//首先选择一个代测的随机数p,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。
//(1) 选择一个小于p的随机数a。
//(2) 设j=0且z=a^m mod p
//(3) 如果z=1或z=p-1,那麽p通过测试,可能使素数
//(4) 如果j>0且z=1, 那麽p不是素数
//(5) 设j=j+1。如果j且z<>p-1,设z=z^2 mod p,然后回到(4)。如果z=p-1,那麽p通过测试,可能为素数。
//(6) 如果j=b 且z<>p-1,不是素数
// 判定是否存在 a^s=1 (mod n) 或a^((2^j)*s)= -1(mod n)(0<=j
bool Witness(int a,int n)
{
// 解释一下数学词汇:
// ceil求不小于x的最小整数,函数原型extern float ceil(float x);求得i的最大值
// log计算x的自然对数,函数原型extern float log(float x);
long i,d=1,x;
for (i=(int)ceil(log((double)n-1)/log(2.0))-1;i>=0;--i)
{
x=d;
d=(d*d)%n;
if ((1==d) && (x!=1) && (x!=n-1))
{
return 1;
}
if ((n-1)&(1<0))
{
d=(d*a)%n;
}
}
return (d!=1);
}
// 参数n,是要测定的数字,s是要内部测试的次数。
bool Rabin_Miller(int n,int s)
{
for (int j = 0;j < s; ++j)
{
int a = rand()*(n-2)/RAND_MAX + 1;// 获得一个随机数1<=a<=n-1
if (Witness(a,n))// 利用这个随即数和n进行判断对比,只要有一次返回true,就说明n不是一个素数
{
return false;
}
}
return true;// 通过验证是一个素数
}
// 算法3:采用Rabin-Miller算法进行验算
// 这个算法是求大素数使用的。所以你的必须想办法支持大数字运算,
// 不然极易造成内存访问失效,我在我的机子上,MAX_NUMBER=10000时就会出现问题,1000就没有问题
void PrimeNumber3()
{
int Max[MAX_NUMBER/2];// 在栈上分配,栈上空间要求一般都在2M之间,
// 如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少
// 所以没有必要申请和所求数字同样大小的空间。
int cout = 0;// 记录素数个数
memset(Max,0,MAX_NUMBER/2);
for(int i = 2; i < 1000; ++i)
{
if(Rabin_Miller(i,20))
{
Max[cout++] = i;
}
}
}
以上程序都经过测试,测试环境Window 2003+VC7.1