哥德巴赫猜想的验证
一、什么是哥德巴赫猜想
?????? 哥德巴赫猜想:任意大于6的偶數,都可以分解為兩個質數的和。
二、哥德巴赫猜想的驗證
方法一:
#include <stdio.h> #include <time.h>#include "mec.h"void checkGoldBech(int num); boolean canResolve(int num); boolean isPrime(int num);boolean isPrime(int num){int n;for(n = 2;n < num && num % n;n ++ ){;}return n >= num; }boolean canResolve(int num){int j;for(j = 3;j <= num/2 ;j += 2){if(isPrime(j) && isPrime(num - j)){ // printf("%d = %d + %d\n",num ,j ,num - j);return TRUE;}}return FALSE; }void checkGoldBech(int num){int i;for(i = 6;i <= num; i += 2){if(!canResolve(i)){printf("哥德巴赫猜想是錯誤的!!\n");return;}}printf("哥德巴赫猜想是正確的!!!\n"); }int main(){int num;long startTime;long endTime;printf("請輸入要查詢的范圍:");scanf("%d",&num);startTime = clock();checkGoldBech(num);endTime = clock();endTime -= startTime;printf("耗時:%d.%03d\n",endTime / 1000,endTime % 1000);return 0; }上述的方法,在判斷一個數是否為質數的函數(isPrime)中,使用了大家最容易想到的操作:即n從0開始循環與num相與,直至n循環到num-1。而恰恰是這個函數最為耗時,使得程序的效率極低。當運行程序時,驗證的位數較大(8位數或者更大)時,耗時極多。因此,我們有必要對此函數進行優化!!
方法二:
boolean isPrime(int num){int n;int midleNum;if(n == 2){return TRUE;}if(num % 2 == 0 && num >2){return FALSE;}midleNum = (int)(sqrt(num) + 1);for(n = 3;n <= midleNum && num % n;n += 2 ){;}return n > midleNum; }方法二在方法一的基礎上,更優化了一步。當傳入一個num時,先判斷是否為2,若是2(質數),直接返回TRUE;若是其它數,先排除所有大于2偶數,然后再對奇數進行判斷。在這里,循環只需要進行到根號下num即可。理由如下:若傳入的數為10000,10000/2 = 5000,則從5001到9999之間,不會存在一個數可以被10000整除;再思考,10000/3 = 3333.33,那么,3333到4999之間就沒必要考慮了;10000 / 4 = 2500,那么,2501到 3332之間就不用考慮了...... 并且,如果我們檢測過了2,那就沒有必要再檢測5000了。綜上,對于10000,我們只需要從2檢測到100就夠了,也就是檢測到根號10000就夠了,
方法三:
?????? 程序再優化:不再對2至根號num的數進行意義判斷,而是直接“得知”這個數是否為質數,這樣就可以極大地提高算法的速度!
?????? 若要求驗證的范圍為num,則,將[2,num)中所有的質數全部找到,并把它們存放在一個擁有num個元素的數組中。假設index在[2,num)之間,以index為下標,array[index]中的值有兩種:0或1,分別代表質數和非質數。
?????? 這樣一來,判斷一個數是否為質數,只需要判斷array[index]中的值即可!
boolean *primePool; //質數池(數組)void screenPrime(int count){int prime = 2;int i;int lastNum;int index;for(index = 4;index < count ;index += 2){primePool[index] = 1;}lastNum = (int(sqrt(count)) + 1);for(index = 3;index <= lastNum ; index += 2){if(primePool[index] == 0){for(i = index * index;i < count;i += index){primePool[i] = 1;}}}} //篩選質數并設置0/1boolean isPrime(int num){return !primePool[num]; //判斷數組元素中的值 }在上面的篩選質數函數(screenPrime)中,我們對質數的判斷又進行了優化。這里要提出一種方法:篩選法。
以上的解釋摘自百度百科。
在這里對篩選法再進行一些解釋,若一個數m是質數,則2*m已經被2篩去了,3*m已經被3篩去了...... 因此從m*m開始篩選即可!相信上述定義對照來看代碼不難理解。
方法四:
方法三仍有優化的地方,它最大的消耗是內存空間!因為需要申請一個長度為num的數組!雖然我們已經使用了boolean 類型,但還是耗費了很多空間。那么,我們是否可以用一個二進制位來表示一個數是否為質數呢?答案是可以。
通過上圖我們可以清晰地看到從數組的第一個元素開始,依次保存0~num的質數性(每個元素保存八個數字的質數性)。這樣一來,就大大地節省了內存空間。
下面,我們只需要宏定義三個量,分別進行“取位”、“清位”、“置位”的操作即可。
#define SETB(value,index) (value |= 1 << ((index)^7)) //置位 #define CLRB(value,index) (value &= ~(1 << ((index)^7))) //清位 #define GETB(value,index) (((value) & (1 <<((index) ^ 7))) != 0) //取位有了這三個宏定義,我們進一步的代碼優化就可以完成了:
void screenPrime(int count){int prime = 2;unsigned int i;unsigned int j;int lastNum;int index;for(index = 4;index < count ;index += 2){SETB(primePool[index >> 3],index & 7);}lastNum = (int(sqrt(count)) + 1);for(i = 3;i <= lastNum ; i += 2){if(!GETB(primePool[(unsigned int) i >> 3],i & 7)){for(j = i * i;j < count;j += i){SETB(primePool[j >> 3],j & 7);}}}}??? 在這種方法中,我們使用了位運算,即對“位”來進行操作。這是計算及內部極其高效的一種手段,因而也極大地提高了程序的效率!!
以上說法若有不周之處,還請各位指點。
總結
- 上一篇: 比较经典的位字段例题(颜色三原色)
- 下一篇: 网络安全红蓝军对抗完整战术周期