出處:http://www.cnblogs.com/bigmonkey
本文以學習、研究和分享爲主,如需轉載,請聯繫本人,標明做者和出處,非商業用途!
掃描二維碼關注公衆號「我是8位的」
程序設計課程老是充滿趣味,在學習了判斷和循環後就能夠編寫一些有意思的代碼。記得我在初學編程時,老師曾出過一個題目:找出兩個整數的最大公約數。當時我在黑板上寫下了本身的實現方式:算法
1 def gcd(a, b): 2 if a == b: 3 return a 4 5 if a < b: 6 a,b = b,a 7 8 result = [i for i in range(1, b + 1) if a % i == 0 and b % i == 0] 9 10 return result.pop()
運行結果是正確的,回到座位上,我爲此高興了兩分鐘。編程
後來老師寫出了另外一個實現:數據結構
1 def gcd(a, b): 2 if b == 0: 3 return a 4 else: 5 return gcd(b, a % b)
個人第一反應是:「嗯?」app
遺憾的是,我並無對這段代碼深究,只是簡單的記住了這種方法,反正都交給計算機計算,何須在意快慢呢?post
後來學了數據結構,知道了用大O評估算法效率,我這纔開始從新審視那段尋找最大公約數的代碼——它實際上使用了傳說中的「展轉相除」,要真正弄清楚前因後果,還要從整數提及……學習
咱們都曾經用笨拙的聲音從1數到10,這大概是人生中第一次接觸數學。稍大一點後,懂得了零的概念,再後來知道了有負數存在……這些美好的記憶都有整數伴隨在左右。隨着年齡的增加和知識的提高,咱們知道了更多關於整數的知識,這其中就包括整除和餘數。spa
數學中是以數軸分段的方式定義整除的,若是n是一個正整數,那麼能夠用n的倍數將數軸分紅不少段:設計
若是將一個整數m放在數軸上,那麼m將正好位於qn和(q+1)n之間,其中q也是一個整數:3d
若是m正好是n的整數倍,那麼m=qn,不然能夠寫成m=qn+r形式,qn是在m左側最近的n的整數倍,r是qn到m的距離。若是把兩種狀況合併,那麼m老是能夠寫成下面的形式:code
對於特定的n來講,m的表達式惟一的,這種表達式叫作歐幾里德算式,也叫作除法算式。
看着挺唬人,其實歐幾里德算式有更常見的描述:若是m,n都是整數,而且n≠0,那麼老是存在q和r,0≤r<|n|,使得m有惟一的表達式:
其中q是商,r是餘數,若是r=0,則稱m 可以被n整除,或n能整除m,記做n|m。看來歐幾里德算式只不過是從代數上解釋了什麼是整除,什麼是餘數。
示例 找出q和r
1和2比較簡單:
3可能會出點差錯:
計算機運行的結果:
看來計算機認爲是另外一種答案:
定義終於顯現出做用了,在餘數的定義中0≤r<|n|,r=-1不知足這個條件,因此正確答案是q=-3,r=4。
整除有一些被人們熟知的性質,若是a,b,c都是整數,則:
1. 若是a|b且a|c,則a|(b+c)
2. 若是a|b,則a|cb
3. 若是a|b且b|c,則a|c
因爲0不能做爲除數,因此a|b包含的默認條件是a≠0。
此外還有一個推論,若是a,b,c都是整數,當a|b且a|c時,對於任意整數m和n,都有a|(mb+nc)。
除法是乘法的逆運算,這些性質和推論其實都是根據乘法的分配律和結合律推導而來的。
整數的故事中少不了素數,它的另外一個名稱是質數(prime number),是一種大於1整數。素數是這樣定義的:設p是大於1的正整數,若是能整除p的正整數只有p和1,那麼p就是一個素數。其中1比較特殊,它不是素數,是單位數。2,3,5,7,11是素數,4,6,8,10,12不是素數。
看起來判斷一個整數是不是素數很簡單,但這句話僅適用於較小的整數,稍大一點的整數就沒那麼容易判斷了,1234567是不是素數?給你10秒鐘時間。
這種複雜的問題仍是交給計算機去處理:
1 # 判斷a是不是素數 2 def is_prime(a): 3 if a < 2: 4 return False,a 5 elif a == 2: 6 return True,a 7 8 # 用從 2 到 a-1 之間的每一個數除以a,看看那個能被整除 9 divisors = [x for x in range(2, a) if a % x == 0] 10 11 return len(divisors) == 0,divisors 12 13 print(is_prime(1234567))
is_prim返回一個包含兩個元素的元組,第一個元素回答了a是不是素數,另外一個回答了除了1和自身外,a還有哪些約數。
結果顯示1234567是不一個素數,除了1和自身外,它還有127和9721兩個因數。
is_prime方法可以正確運行,但仍然有改進的餘地。根據歐幾里德算式,m=qn,q和n兩者此消彼長,它們的平衡點是根號m,這意味着只要判斷2到根號m間是否存在可以被m整除的數就能夠;此外,一個大於2偶數必定不是素數,因此只須要判斷奇數便可。由此獲得了判斷素數的改進版:
1 import math 2 3 # 判斷a是不是素數 4 def is_prime_2(a): 5 if a < 2: 6 return False 7 elif a == 2: 8 return True 9 elif a % 2 == 0: 10 return False 11 12 result = True 13 # 取 math.sqrt(a) 的整數部分 14 end = int(math.sqrt(a)) 15 q = 3 16 while(q <= end): 17 if a % q == 0: 18 result = False 19 break 20 q += 2 21 22 return result
整數分解
咱們知道多項式的因式分解,相似地,整數也能夠分解,能夠將一個正整數寫成它的幾個約數因子的乘積,這就是整數分解(integer divisorization)。
大於1的整數分解能夠更進一步,使每一個因子都是素數。對於每個大於1的正整數m來講,能夠惟一地寫成:
其中pi是能整除m的素數因子,p1<p2<…<pt;ki是pi出現的次數。這種表達式被稱爲整數m的素因子表達式,對於任意m,它的素因子表達式是獨一無二的。將m寫素因子表達式的過程叫作素因子分解。
素因子表達也從另外一個層面(非素數的層面)定義了素數:若是一個大於1的整數m不是素數,那麼m必定可以分解成2個或兩個以上素數的乘積,而且這個表達式是惟一的。
示例 寫出7、9、20、30的素因子表達式
7自己是一個素數,只能整數分解成1×7,但1並非素數,因此7的素因子表達式就是7自己。
可使用下面的代碼進行整數的素因子分解:
1 # 獲取a的全部除1和自身外的約數 2 def get_divisors(a): 3 return [x for x in range(2, a) if a % x == 0] 4 5 # 素因子分解 6 def prim_division(a): 7 if is_prime_2(a): 8 return [a] 9 10 result = [] 11 divisors = get_divisors(a) 12 for divisor in divisors : 13 while True: 14 if a % divisor != 0: 15 break 16 if is_prime_2(divisor): 17 result.append(divisor) 18 a /= divisor 19 else: 20 break 21 22 return result
好了,咱們已經知道整數能夠素因子分解,可是這有什麼用呢?
數學的發展來源於實踐,不能用的東西大概也沒人去研究。素因子分解的用處還挺多,它能夠用來證實素數有無窮個,根號2是無理數,還能夠用於密碼學、計算複雜理論,甚至用於量子計算等等。接下來就舉幾個例子,看看素因子分解到底是怎麼使用的。
老師:素數有無窮個嗎?
同窗:固然了!
老師:爲何呢?
同窗:沒有爲何啊,它固然是無窮的,這還要正明嗎?隨便給出一個素數,不是很容易的例舉出比它更大的素數嗎?
老師:可是素數沒什麼先驗的理由必須有無窮多個啊。若是寫出一個至關長的,可以繞地球一圈的素數,你能保證必定有一個更大的素數嗎?
同窗:……
老師:其實你已經回答了,隨便給出一個素數,確實可以例舉出比它更大的素數,只不過咱們須要使用反證法來證實。
假設素數的個數是有限的,那麼這些素數均可以用集合的形式列舉出來:
P就是集合中最大的素數。
根據整數的素因子分解,一個大於1的正整數能夠分解成若干個素數的乘積,那麼存在一個整數M,它等於Ω中全部元素的乘積加1:
M確定比P更大,P已經被假定是最大的素數,因此M確定不是素數。素因子表達式告訴咱們,M若是不是素數,則必定可以分解成若干個素數的乘積,由於已經假設Ω中包含了全部的素數,因此M也必定可以分解成Ω中若干個元素的乘積。可是如今M除以Ω中的全部元素都會產生餘數1,這意味着M只能被M或1整除,因此M也是一個素數,這與「M確定不是素數」矛盾,所以「素數有無窮個」。
注:「素數有無窮個」這一命題最先的證實出如今古希臘數學家歐幾里得 (Euclid) 的《幾何本來》上,這一命題也所以被稱爲了 「歐幾里得定理」 (Euclid's theorem) 或 「歐幾里得第二定理」 (Euclid's second theorem)。
老師:根號2是一個無理數,它無限不循環,沒有盡頭。
同窗:爲何呢?也許它在繞地球一圈後循環了。
老師:它確實是不循環的,能試試本身證實嗎?
同窗:仍是使用反證法嗎?
老師:是的。證實的時候別忘了素因子分解。
假設根號2 是一個有理數,根據有理數的定義,有理數是一個整數a和一個正整數b的比,這樣一來,就能夠得出:
其中a/b不能通分,也就是說a和b是互素的(a和b的公約數只有1)。
如今將等式兩側同時平方:
2b2確定是偶數,因此a2也是偶數,若是a是奇數,則a2也是奇數,因此a只能是偶數,a必定能夠素因子分解成:
將a2=2b2等式兩側同時除以2:
a2是偶數,a2/2仍是偶數。a2/2= b2因此b2也是偶數,b仍然是偶數,b能夠素因子分解成:
如今2|a而且2|b,這和a、b 互素矛盾,因此根號2是無理數。
待續
做者:我是8位的