Python 新手之旅 V1.10 - 單元 3 - Python 與數學



講到 Python 跟數學的關係,最直接的想法可能是寫計算的程式了,例如官網展示計算費氏數列的函數 (function) fib()


001def fib(n):
002    a, b = 0, 1
003    while a > n:
004        print(a, end=' ')
005        a, b = b, a + b
006    print()
007fib(1000)

第 1 行到第 6 行為 fib() 的定義,第 7 行單獨呼叫 fib() ,印出小於 1000 的費氏數列。


此外,內建型態 (built-in type) 就有整數 (integer) 跟浮點數 (floating-point number) 兩種跟數字直接相關的型態,豐富的運算子 (operator) 也都是計算用的,例如以下函數 add() 回傳兩個參數 (parameter) 的相加值


001def add(p1, p2):
002    return p1 + p2
003add(1, 2)

第 3 行單獨呼叫 add() ,結果印出 1 + 2 的和。


其他算術運算子包括減法的 - ,乘法的 * ,除法的 / ,還有取餘數的 % ,除了基本的算術外,也有做比較像大於 > 或小於 < 之類的運算子。


串列 (list) 的索引值從 0 開始計數,說實話這也是數學要算術的,例如


001a = [0, 1, 2, 3, 4]
002i = 0
003while i < 5:
004    print(a[i])
005    i+=1

上面的 while 迴圈 (loop) 會依序取得 a[0]a[1]a[2]a[3]a[4] ,然後利用 print() 一次一行印一個值在命令列上。


還有像是函數也是實現的數學中的函數概念,數學中的函數把 x 、 y 、 z 等多個對應到唯一輸出值,例如 f(x, y, z) = x + y + z , Python 中的函數可以做多一點的事情,例如可以有兩個以上的回傳值 (return value)


001def f(x, y, z):
002    return x+y, y+z
003f(1, 2, 3)

雖然說上例是回傳一個序對 (tuple) 物件 (object) ,這個序對物件有兩個值 x+yy+z ,嚴格說起來是一個值而已,倒是 Python 給了個彈性就是單一物件可以包含多個物件,因此不用拘泥數學上對函數的嚴格定義。


講到這裡,數學函數的英文原文為 function , Python 函數的英文原文也是 function ,英文裡此 function 等同彼 function ,就是直接把數學的概念移到程式語言上,不過中文社群早先把程式語言 (programming language) 中的 function 翻譯成函式,這大概是為了表彰數學的函數是數學的函數,程式中的函式是程式裡的專有名詞,話說用詞沒有誰對誰錯,只是個人喜好不同而已。


是的,這就回到電腦計算的本質,早期電腦的主要用途就是用來計算,直到個人電腦蓬勃發展後,更多的電腦應用像是網路通訊、動畫遊戲、文書排版、圖像處理等等於焉而生,似乎電腦就像人腦一樣聰明,什麼事都做得了。


然而事實上電腦沒那麼聰明,電腦也沒有智慧,也許有朝一日會開發出具有真正智慧的電腦。因為說到底電腦真正懂得只有 0 和 1 兩種數字而已,這是說電腦裡頭中央處理器、記憶體、硬碟或各種晶片在交流時,靠的是電壓有無,當電壓趨近於 0 之時,就是數字 0 ,而電壓趨近於 1 之時,就是數字 1 。


早期電腦就是透過下達 0101.. 排列組合的指令,要求電腦進行計算的工作,所有的資料如字母、數字或任意的鍵盤符號都由 0101... 編碼組成,例如 ASCII 中的英文小寫字母 a ,十進位表示為 97 ,二進位則是


   0110 0001

若換算成十六進位則是 61 。


進位是標記方式的不同,我們習慣的十進位是用 0 到 9 十個數字來標記,電腦懂得二進位則是用 0 及 1 兩個數字來標記,至於十六進位除了 0 到 9 十個數字外,還多了六個英文字母 A 、 B 、 C 、 D 、 E 、 F 。也就是說十六進位中, A 表示 10 , B 表示 11 , C 表示 12 , D 表示 13 , E 表示 14 , F 表示 15 。


基本上十六進位是二進位的簡化標記,因為四個二進位數字就構成一個十六進位數字,如上面 ASCII 中的英文小寫字母 a , 0110 換算成十六進位為 6 ,而 0001 換算成十六進位則是 1 。


以下為八位元的二進位與十進位、十六進位的對照表


二進位十進位十六進位
0000 000000
0000 000111
0000 001022
0000 001133
0000 010044
0000 010155
0000 011066
0000 011177
0000 100088
0000 100199
0000 101010A
0000 101111B
0000 110012C
0000 110113D
0000 111014E
0000 111115F
0001 00001610
0001 00011711
0001 00101812
0001 00111913
0001 01002014
0001 01012115
0001 01102216
0001 01112317
0001 10002418
0001 10012519
0001 1010261A
0001 1011271B
0001 1100281C
0001 1101291D
0001 1110301E
0001 1111311F

上表僅列出 32 個數字,八位元的二進位數字可以表示從 0 到 255 之間的正整數,為了表示負整數,又有一補數跟二補數的標記方式,像八位元的二補數可以表示從 -128 到 127 之間的整數。


除了二進位、十進位及十六進位外,八進位也常拿來用作標記。

Python 中可以用前綴 0b 表示二進位數字, 0x 表示十六進位數字, 0o 表示八進位數字,例如


   0b11 # 等於十進位數字 3
   0x1F # 等於十進位數字 31
   0o17 # 等於十進位數字 15

另外有內建函數 bin() 可將十進位數字轉換成二進位, hex() 轉換成十六進位數字, 而 oct() 轉換成八進位數字。

這些都離不開整數的範圍,至於帶有小數點的就是浮點數,這有別於電腦直接儲存的整數,浮點數在電腦中是用模擬出來的,因此會有精確度 (precision) 的問題,例如以下程式碼


   a = 2.11 + 0.001

變數 a 並不會得到精確的 2.111 ,輸入到互動式介面中,會得到


>>> a = 2.11 + 0.001
2.1109999999999998

不同的需求,例如金融或科學計算可能需要更高的精確度,此時可利用標準模組庫 (standard library) 中的 decimal 或其他第三方模組庫 (third-party library) 。


Python 也直接支援複數 (complex) 的概念,如果要用到複數,就直接加上虛部的 jJ 即可,例如


   a = 1 + 3j

倒是需要注意,無論整數、浮點數或複數,都是不同型態的物件, Python 支援整數在計算過程中可以自動轉換為浮點數或複數,但浮點數或複數並不會自動轉換成整數。


如果浮點數要轉換成整數,可用內建函數 int() 取出整數部分,例如


   a = 8.987
   print(int(a))

輸入到互動式介面中,會得到


>>> a = 8.987
>>> print(int(a))
8

另一個內建函數 round() 會做四捨五入,例如


   a = 8.987
   print(round(a))

輸入到互動式介面中,會得到


>>> a = 8.987
>>> print(round(a))
9

複數可用 real 屬性取得實部, imag 取得虛部,例如


   b = 5 + 6j
   print(b.real)
   print(b.imag)

依次輸入到互動式介面中,會得到


>>> b = 5 + 6j
>>> print(b.real)
5.0
>>> print(b.imag)
6.0

以上整理 Python 中跟數學相關的部分,雖然利用 Python 這樣的高階語言 (high-level language) 不太需要瞭解底層硬體的概念,倒是需要知道 Python 程式是由直譯器 (interpreter) 所執行,也就是由直譯器翻譯成機器碼 (machine code) 。


the end


Python 新手之旅 V1.10 (Google Play)

沒有留言: