(六)演算法 1 測試素數

2021-10-24 22:15:38 字數 3219 閱讀 5437

數論中的乙個重要問題是確定乙個數是否為素數。

素數在研究編碼的密碼學(cryptography) 中起著重要的作用。

在現代電子通訊領域中,計算機經常用於執行編碼和解碼操作。許多可用的、最好的編碼技術都是基於素數。

設計乙個確定整數n是否為素數的函式,思路:

如果直接從素數的定義出發,最直接的方法是,檢查是否有兩個約數。

由於n的約數必須小於等於n,因此只要檢查所有1到n之間的數,就會找出所有的約數。

決定n是否為素數,步驟:

(1) 檢查1到n之間的每個數,看它是否能整除n。

(2) 每次遇到乙個新約數,計數器加1。

(3) 在所有的數都被測試以後,檢查約數計數器的值是否為2。

isprime取乙個整數n,返回乙個布林值,是乙個謂詞函式。

**實現如下:

#include

#include

/* determine if it is prime. */

/* function prototype */

bool isprime

(int n)

;/* main program */

main()

else

}/* function */

bool isprime

(int n)

return

(count ==2)

;}

isprime函式表示了確定乙個數是否為素數的演算法。

為了說明它確實是乙個演算法,結合演算法必須滿足的三個要求,加以說明:

(1) 定義是明確的,無二義性的。

當用一種程式語言表示乙個演算法時,該語言的定義指定精確的解釋。

乙個正確執行的編譯器只會以一種確定的方法解釋語句。

在程式語言中,某一語句的意義稱為語言的語義(semantic) 。

(2) 有效性,即它的步驟都是可執行的。

以程式形式表示的演算法有助於滿足這個要求。

c程式語言的語義為程式中的每一種結構指定了它的意義,編譯器會產生機器執行所必需的指令。

(3) 有限性,即在執行有限步後演算法會結束。

通過檢查程式的結構發現,函式中僅有的長期執行的部分是乙個for迴圈,將執行n個週期,最終是會返回的。

對於簡單程式,通過說明維護了相應的迴圈不變式,可以容易地說明程式的正確性。

對於複雜程式,存在兩種方法可以增加對程式正確性的把握:

(1) 桌面檢查(desk-checking)

按著程式**一步一步執行,確信程式的行為和要求一致。

(2) 測試(testing)

利用盡可能多的測試例項執行程式,對每種情況都檢查執行結果是否正確。

常見錯誤:

當寫乙個程式時,盡量徹底地測試程式是很重要的。

儘管這樣,程式中還會有許多測試沒有發現的錯誤,因為通常不可能將每一種可能出現的情況都測試一下。

1.1小節演算法的效率比較低。

改善isprime執行的效率,存在以下三種策略:

(1) 只要發現任何大於1小於n的約數,就能停下來報告n不是素數。

需要改變程式結構,一旦發現了約數,函式立即返回。

(2) 一旦函式已經檢查了n是否能被2整除,就不需要檢查它是否能被其他偶數整除。

因此,一旦確定n不可能被2整除,只需要檢查奇數。

(3) 該程式不需要試探任何大於n的平方根的約數。

因為n等於d

1d_1

d1​xd

2d_2

d2​,如果其中乙個因子大於n的平方根,那麼另乙個一定小於n的平方根。

因此,如果n有任何約數的話,肯定有乙個小於它的平方根。

這意味著,程式中的for迴圈只要執行i≤n

i \leq \sqrt n

i≤n​

次。**實現如下:

#include

#include

#include

/* function */

bool isprime

(int n)

return true;

}

常見問題:

(1) 當設計乙個通用演算法時,考慮是否存在使通用演算法失敗的特例是很重要的。如果存在這種特例,必須確保在程式中明確地處理這些特例。如:

if

(n <=1)

return false;

if(n ==2)

return true;

(2) 當在某一程式中使用迴圈時,檢查一下是否在迴圈中存在某些放在迴圈開始前執行更好的計算。如果存在,則可以計算一次結果,把它存在乙個變數裡,然後在迴圈中使用這個變數,從而改善程式的效率。

正確:

limit =

for(i =

3; i <= limit; i +=2

)...

錯誤:

for

(i =

3; i <=

sqrt

(n)+

1; i +=2

)...

在每個for迴圈週期中都要呼叫sqrt函式, 儘管每一次迴圈返回的結果都是相同的。—— 效率低

(3) 對浮點數判斷嚴格的相等是很危險的,該實現的正確性取決於硬體如何執行浮點數運算。

為了確保起見,函式總是多檢查乙個可能的約數。

此外,將limit宣告為int型別,從而確保for迴圈控制行中所用的所有值都是整數。

正確:

int limit;

limit =

sqrt

(n)+

1;

錯誤:

double limit;

limit =

sqrt

(n);

isprime的 最初版本 vs 新版本:

最初版本可讀性好,而新版本執行效率高。

當為某乙個問題選擇乙個演算法時,最關心的是正確性。使程式更加有效是乙個極好的目標,但不要為了追求效率而使程式給出錯誤的答案。

保證了正確性以後,影響程式設計成功與否的重要因素,包括:

效率、清晰度和可維護性。

參考《c語言的科學和藝術》 —— 第6章 演算法

Miller Rabin素數測試演算法模板對比

昨天在usaco做了一道判斷素數的題,就想著學習一下miller rabin素數測試演算法,在網上找到兩種模版,第一種十分簡潔,執行速度也很快,但是會判錯極少的幾個非素數 第二種比較麻煩,執行速度很慢,所以我便想找到第一種模版不能判斷的非素數特判一下,結果用了一天,電腦只找到10 8以下的,10 9...

大素數測試

關鍵字 keywords 大素數 高效 快速 測試 檢測 驗證 先列出幾篇已經寫過的大素數測試的文章 基本都是用miller rabin的測試方法 但似乎都沒有實現完整的 另外對於miller rabin的方法還有可以改進的地方 miller rabin的演算法 我們的問題是給定乙個數n,想判斷它到...

數論 素數測試

檢查乙個正整數是否是素數稱作素數測試。基本素數判別法 正整數n是素數,當且僅當它不能被任何乙個小於根號n的素數整除 埃拉託斯尼斯篩法 先把n個自然數按次序排列起來。1不是 質數,也不是 合數,要划去。第二個數2是 質數留下來,而把2後面所有能被2 整除的數都劃去。2後面第乙個沒劃去的數是3,把3留下...