每個程式設計師都應該知道的基礎數論
這篇文章討論了數論中每個程式設計師都應該知道的幾個重要概念。本文的內容既不是對數論的入門介紹,也不是針對數論中任何特定演算法的討論,而只是想要做為數論的一篇參考。如果讀者想要獲取關於數論的更多細節,文中也提供了一些外部的參考文獻(大多數來自於 Wikipedia 和 Wolfram )。
0、皮亞諾公理
整個算術規則都是建立在 5 個基本公理基礎之上的,這 5 個基本公理被稱為皮亞諾公理。皮亞諾公理定義了自然數所具有的特性,具體如下:
(1)0是自然數;
(2)每個自然數都有一個後續自然數;
(3)0不是任何自然數的後續自然數;
(4)不同自然數的後續自然數不同;
(5)如果集合S包含了數字0,並且包含S中每一個數字的後續自然數,那麼集合S就包含了所有的自然數。
上述第5個公理也被稱為“數學歸納法的基礎”。
通常,除了我們想要證明其他算術定理的情況,我們很少直接使用上述公理。但作為算術的基石,這些公理是值得我們去了解的。
1、算術基本定理和除法運演算法則
正如這個定理的名稱所言,算術基本定理是數論中所有概念的核心。算術基本定理含義如下:任何一個大於1的整數都可以以某種特定的方式寫成質數的乘積的形式(這種特定方式取決於乘積中質數的順序)。例如,18 = 2 * 9, 1755 = 33 *5 * 13. 這個定理在幾乎所有的數論運演算法則中都扮演著十分重要的角色,例如求一個數的質數因子、最大公約數、除數的和等等。想要證明這個定理其實很簡單,實際上它是歐幾里得第一個定理的一個推論(下面小節會討論到)。
除法運演算法則含義是說:給定兩個整數a,b(b不等於0),那麼存在兩個整數q和r使得下面的等式成立:
a = bq + r, 0 <= r < b
通常我們把q稱為商,而把r稱為餘數。如果r = 0,那麼我就說b整除a,並且表示為:b | a.
2、歐幾里得定理
數學中兩個重要定理,被稱為“歐幾里德的第一定理(或歐幾里德的引理)”和“歐幾里德的第二定理(通常簡稱為”歐幾里德定理“),內容如下:
第一定理:p|ab => p|a or p|b。該定理的直接結論就是算術基本定理。
第二定理:質數的數量是無限的。有很多簡單的證明方法。
雖然確實存在無限多的質數,但也應該記住,質數之間存在任意大的差值。換句話說,給定n的前提下,總是可以獲得一些列的n個連續複合數。
延伸閱讀:Euclid's Theorem、Euclid's Lemma、walfram
3、最大公約數、最小公倍數和貝祖定理
歐幾里得演算法是求兩個數的最大公約數最常用的演算法,而且也是一個很高效的演算法,因為使用歐幾里得演算法求解兩個數的最大公約數的演算法步驟最多不會超過這兩個數中較小的那個數的5倍。最大公約數通常使用圓括號表示—— (a,b) 表示a和b的最大公約數。類似地,最小公倍數通常使用方括號表示—— [a,b] 表示a和b的最小公倍數。
如果 (a,b) = 1,即 [a,b] = ab,此時我們稱a和b互質。
如果 (a,b) = d,那麼 (a/d,b/d) = 1。
最大公約數和最小公倍數之間的關係可以由一個非常簡單的等式來表示:(a,b) * [a,b] = ab. 該等式為我們提供了一種快速計算兩個數的最小公倍數的方法。
貝祖定理是說,如果 d = (a,b) 那麼一定存在整數 x 和整數 y 滿足 ax + by = d. (當然,如果存在的話,那麼線性雙變數方程的理論保證了無窮多解的存在性)。同樣值得注意的是,k = d 是滿足 ax + by = k 有一個關於 x 和 y 的解的最小正整數。
指定 a 和 b,我們可以通過遞迴或迭代的方式實現擴充套件的歐幾里得演算法來求解滿足等式 ax + by = d 的 x 和 y。
延伸閱讀:GCD、Bezout's Identity、Euclid's Algorithm、Extended Euclid's Algorithm
4、整數因式分解
整數因子分解的最常用的演算法是 Eratosthenes 篩選法。在分解N時,將質數掃描到 sqrt(N)就足夠了。另外,如果我們需要對 1 到 N 之間的所有數字進行因式分解,則可以使用該演算法的單次執行來完成此任務 - 對於 1 到 N 之間的每個整數 k ,我們可以保持一對對映——整除 k 的最小質數、最大倍數,(p,a)。k 的剩餘質因子與 k/(pa) 的相似。
延伸閱讀:wikipedia、 interactive animation
5、線性同餘方程組
形如ax≡b (mod n)的方程式(x是未知數)稱為線性同餘。當且僅當存在整數x使得n | (ax-b)成立時,這樣的方程組將有一個解,即ax -b = ny,y是整數,換句話說,ax + n(-y)= b。我們已經從Bezout的等式中得知,像這樣的線性不定方程將只有在(a,n)的gcd(假設該值為d)整除b時才有解。在這種情況下,讓b = dd',a = da',n = dn',所以我們有:
da'x + dn'( - y)= dd',其中gcd(a',n')= 1
帶入變數d
a'x + n'( - y)= d'。
由於gcd(a',n') = 1,現在我們可以使用擴充套件的歐幾里德的演算法來找到a'x + n'( - y)= 1的解,然後將該解乘以d'得到對於a'x + n'( - y)= d'的解。
注意,如果ax≡b(mod n)有一個解,則mod(n / d)有且僅有一個解。如果這個解是用x0表示的,那麼mod n將恰好有d個解,由x0 + kn/d給出,其中0<= k<d。在關於二次方程的教程中詳細討論了這一點。
延伸閱讀:Linear Congruence Theorem、Solving Linear Congruences
6、中國剩餘定理
典型的問題形式是“尋找一個數,除以2餘1,除以3餘2,除以7餘5”其餘各項可以被推廣為一元線性同餘方程組之後可以使用中國剩餘定理來解決。舉個例子,下面的問題可以被表示為三個線性同餘式:“x ≡ 1 (mod 2), x ≡ 2 mod(3), x ≡ 5 mod (7)”
也就是一元線性同餘式方程組:
x ≡ a1 (mod n1)
x ≡ a2 (mod n2)
x ≡ a3 (mod n3)
....
x ≡ ak (mod nk)
假設整數ni,nj兩兩互質,則對任意的n=n1n2...nk,方程組有解
對於任意的i,當0 <= di < ni,令ci=n/ni,令di為同餘式cix=1(mod ni)的解(這個解法可以在利用擴充套件的歐幾里德演算法)。上面的線性方程組的通解可以給出為:
c = a1c1d1 + a2c2d2 + ... + akckdk
中國剩餘定理的直接推論如下:假設 n = p1a1 * p2a2 * .... * pkak 為 n 的素因子分解。 那麼,對於任何整數 a 和 b,我們對於每個 i 都有 a = b (mod n) iff a = b (mod piai ) 。
討論一下 Ni 的不一定都是兩兩互質的中國剩餘定理的推廣,如下 - 線性同餘系統
x≡a1(mod n1)
x≡a2(mod n2)
x≡a3(mod n3)
....
x≡ak(mod nk)
有解,當對於每個 i != j 都有 iff gcd(ni,nj) 除 (ai-aj) ,且存在唯一解 mod n,其中 n 是 n1,n2 ... nk 的最小公倍數
進一步閱讀:中國剩餘定理,求解線性同餘,小程式
7、二次方一致性
給定 q 和 n,如果等式 x2≡q(mod n) 具有解,則 q 稱為二次殘差的模 n。如果該方程不具有解,則q被稱為“二次非殘差”。例如,x2≡9(mod 15)具有解 x = 12,因此 9 是模 15 的二次餘數。另一方面,等式 x2≡11(mod 15)沒有解,因此 11 是二次非殘差,為了簡單起見,如果一個正方形可以取一些正整數 n 的形式(nk + q),則整數 q 是模 n 的二次餘數。
發現具有質數模的二次一致性是否具有一個解,是有些容易的:x2≡a(mod p)只有在(p-1)/ 2 = 1(mod p)時才具有解。 在這種情況下,可以使用 Shank-Tonelli 演算法來獲得解決方案。
延伸閱讀: 二次殘差、二次互反性、模擬、Shank-Tonelli演算法、E4手冊
8、尤拉 Phi 函式、除數函式、約數和、Mobius 函式
尤拉的 Phi 函式 (又稱為常數函式,由φ表示)是自然數的函式,給出與相應的自然數互質的正整數的數目。因此,φ(8) = 4, φ(9) = 6 等。 該函式的以下屬性值得注意:
a) 如果 p 是素數,則 φ(pk) = (p-1)pk-1
b) φ 函式是乘法的,即如果 if (a,b) = 1 則 φ(ab) = φ(a)φ(b)。
c) φ(n) 的值可以通過尤拉公式獲得:令 n = p1a1 * p2a2 * .... * pkak 是 n 的素因子分解。則
φ(n) = n * (1- 1/p1)) * (1- 1/p2)) * ... * (1- 1/pk))
d) 以程式設計方式,如果我們欲求 1 到 n 的 φ , 那麼我們可以非常好地使用篩選演算法連同 φ 的乘法性質。中心思想是:如果 n 是素數,則 φ(n) = n-1。否則,如果 n 是素數的冪,例如 n= pk,則 φ(n) = (p-1)pk-1。否則,對於某個素數p,令 n=pk*q 。使用乘法屬性, 我們有 φ(n) = φ(pk)φ(q)
φ(n) 的兩個重要屬性:
i. aφ(n) ≡ 1 (mod n) 每當 (a,n) = 1。 具體來說, 對於素數p,如果 p 不能整除 a,則 ap-1 ≡ 1 (mod p)。 這種特化也被稱為費馬小定理。
ii. 令 d1, d2, ...dk 為 n 的所有除數(包括 n)。則 φ(d1) + φ(d2) + ... + φ(dk) = n
例如,18的除數是1、2、3、6、9 和 18。觀察到 φ(1) + φ(2) + φ(3) + φ(6) + φ(9) + φ(18) = 1 + 1 + 2 + 2 + 6 + 6 = 18
該除數函式,表示為 d(n),給出了一個自然數的除數的數目。例如,d(18) = 6。類似地,除數函式之和,表示為 σ(n),給出了 n 的除數的和。 因此,σ(18) = 1+2+3+6+9+18 = 39。關於這兩個函式以下屬性毫無價值:
a) 如果 p 是素數,則 d(p) = 2。另外, d(pk) = k+1, 並且 σ(p) = p+1
b) 如果 n 是兩個不同的素數的乘積,假使 n = pq, 則 σ(n) = n+1+(p+q)。另外觀察到這種情況:φ(n) = n+1-(p+q)。
c) 一般來說,令 n = p1a1 * p2a2 * .... * pkak 。則 d(n) = (a1+1) * (a2+1) * ... (ak + 1),並且 σ(n) 由以下乘積給出:
σ(n) = ( (p1(a1+1) - 1) / (p1-1) ) * ( (p2(a2+1) - 1) / (p2-1) ) * ... * ( (pk(ak+1) - 1) / (pk-1) )
如果 σ(n) =2n,則 n 被稱為“完全數”。換句話說, 完全數的真因子(即除了自身以外的除數)的和恰好等於它本身。
mobius函式µ(n) 在所有正整數中定義如下:
在 n 是非平方數(即 n 是不能被任意整數平方得到)並且 n 有偶數個不同的素數因子,則 µ(n) = 1
在 n 是非平方數(即 n 是不能被任意整數平方得到)並且 n 具有奇數個不同素數因子,則µ(n) = -1
在 n 是平方數,即 n 是某個整數的平方,則 µ(n) = 0
Mobius 函式是乘法分配性的,即 a 和 b 互為質數,則 µ(ab) = µ(a)*µ(b).
計算尤拉方程函式的一個有用公式可以用 mobius 函式給出:令 d1,d2,... dk 為 n 的所有除數。然後
φ(n) = (d1 * mu (n/d1) ) + (d2 * µ(n/d2) ) + .... + (dk * µ(n/dk) )
這也可以寫成:
φ(n) = (µ(d1) * (n/d1) ) + (µ(d2) * (n/d2) ) + .... + (µ(dk) * (n/dk) )
使用篩選法計算 phi[n] 的 Java 實現如下:
//read/get n
int phi[] = new int[n+1];
for(int i=2; i <= n; i++) phi[i] = i; //phi[1] is 0
for(int i=2; i <= n; i++)
if( phi[i] == i )
for(int j=i; j <= n; j += i )
phi[j] = (phi[j]/i)*(i-1);
階乘
階乘是非常重要的。N 的階乘定義如下:N = (N)*(N-1)*(N-2)*(N-3)...1。在計算 nPr nCr 時需要使用階乘。他們像這裡描述的那樣很快變得非常大,所以他們需要非常仔細的處理大數、大整數表示等。
延伸閱讀:尤拉的 Totient 函式、除數函式、除數和總和、Mobius函式
到此我們完成了對基本數理論概念的討論。對於那些對數理論感興趣的人,這裡有一些值得一讀的書——
An introduction to the theory of numbers: by Niven, Zukerman and Montgomery (數論導論)
Elementary Number Theory : by David Burton (數論基礎)
整數序列
流行的整數序列有很多。它們中的許多都基於遞迴關係。主要的定理被廣泛用於瞭解其複雜性,邊界與迴圈的關係。很多流行的整數序列,例如:費布那切數列,魯卡斯數字, 斯特恩雙原子數字, 懶卡特數字, 帕多萬數字 還有多邊形數字,諸如 五角形數字, 六角形數字。
公眾號內回覆“1”帶你進粉絲群!
相關文章
- 每個程式設計師都應該知道的 15 個最佳 PHP 庫程式設計師PHP
- 每個程式設計師都應該讀的書程式設計師
- 每個程式設計師都該知道的編碼準則程式設計師
- 每個程式設計師都應該知道的下一個程式語言——Kotlin程式設計師Kotlin
- 每個程式設計師應該知道12件事程式設計師
- 每個程式設計師應該知道的12個API程式設計師API
- 每個Python新手都應該知道的程式設計技巧Python程式設計
- 每個程式設計師都該知道的五大定律程式設計師
- 程式設計師都應該知道的福利程式設計師
- 每個程式設計師都應該成為架構師程式設計師架構
- 每個程式設計師都應該讀《Unix程式設計藝術》程式設計師
- 每個程式設計師都該知道的10大編碼原則程式設計師
- 每個Android程式設計師應該知道的KotlinAndroid程式設計師Kotlin
- 國外程式設計師推薦:每個程式設計師都應該讀的非程式設計書程式設計師
- Rework:每個程式設計師都應該讀的一本書程式設計師
- 每個程式設計師都應該學會分解複雜的方法程式設計師
- 每個程式設計師都應該瞭解的硬體知識程式設計師
- 每個程式設計師都應該參加一次 GDD程式設計師
- 每個程式設計師應該知道的計算機網路知識程式設計師計算機網路
- 關於 Unicode 每個程式設計師應該知道的 5 件事Unicode程式設計師
- 關於Unicode,字符集,字元編碼,每個程式設計師都應該知道的事Unicode字元程式設計師
- 每個程式設計師都應該瞭解的記憶體知識程式設計師記憶體
- 每個程式設計師都應該學習使用Python或Ruby程式設計師Python
- 每個程式設計師都該閱讀的10本書程式設計師
- 程式設計師應該知道的 13 個設計技巧程式設計師
- 每個程式設計師都應當知道的編譯器優化知識程式設計師編譯優化
- 每個開發者都應該知道的33個JavaScript概念JavaScript
- IT職場:每個黑帶都應該知道的事
- 程式設計師都應該知道的福利【必知必懂】程式設計師
- 每個Java軟體架構師都應該知道的20件事Java架構
- 每個程式設計師都應該瞭解的一件事程式設計師
- Java程式設計師應該知道的10個物件導向理論Java程式設計師物件
- 為什麼每個程式設計師都應該懂點前端知識?程式設計師前端
- 每個程式設計師都應該經歷一次軟考薦程式設計師
- 國外程式設計師推薦:每個程式設計師都應讀的書程式設計師
- 設計師都應該知道的ICON知識
- 每個人都應該懂點函數語言程式設計函數程式設計
- 每個 Java 開發者都應該知道的 5 個註解Java