整數的故事(1)

  程序設計課程老是充滿趣味,在學習了判斷和循環後就能夠編寫一些有意思的代碼。記得我在初學編程時,老師曾出過一個題目:找出兩個整數的最大公約數。當時我在黑板上寫下了本身的實現方式:算法

 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兩個因數。

尋找素數2.0版

  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個或兩個以上素數的乘積,而且這個表達式是惟一的。

 

  示例  寫出792030的素因子表達式

  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是一個無理數,它無限不循環,沒有盡頭。

  同窗:爲何呢?也許它在繞地球一圈後循環了。

  老師:它確實是不循環的,能試試本身證實嗎?

  同窗:仍是使用反證法嗎?

  老師:是的。證實的時候別忘了素因子分解。

  假設根號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位的

  出處:http://www.cnblogs.com/bigmonkey

  本文以學習、研究和分享爲主,如需轉載,請聯繫本人,標明做者和出處,非商業用途! 

  掃描二維碼關注公衆號「我是8位的」

相關文章
相關標籤/搜索