講到 Python 跟數學的關係,最直接的想法可能是寫計算的程式了,例如官網展示計算費氏數列的函數 (function) fib()
001 | def fib(n): |
002 | a, b = 0, 1 |
003 | while a > n: |
004 | print(a, end=' ') |
005 | a, b = b, a + b |
006 | print() |
007 | fib(1000) |
第 1 行到第 6 行為 fib() 的定義,第 7 行單獨呼叫 fib() ,印出小於 1000 的費氏數列。
此外,內建型態 (built-in type) 就有整數 (integer) 跟浮點數 (floating-point number) 兩種跟數字直接相關的型態,豐富的運算子 (operator) 也都是計算用的,例如以下函數 add() 回傳兩個參數 (parameter) 的相加值
001 | def add(p1, p2): |
002 | return p1 + p2 |
003 | add(1, 2) |
第 3 行單獨呼叫 add() ,結果印出 1 + 2 的和。
其他算術運算子包括減法的 - ,乘法的 * ,除法的 / ,還有取餘數的 % ,除了基本的算術外,也有做比較像大於 > 或小於 < 之類的運算子。
串列 (list) 的索引值從 0 開始計數,說實話這也是數學要算術的,例如
001 | a = [0, 1, 2, 3, 4] |
002 | i = 0 |
003 | while 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)
001 | def f(x, y, z): |
002 | return x+y, y+z |
003 | f(1, 2, 3) |
雖然說上例是回傳一個序對 (tuple) 物件 (object) ,這個序對物件有兩個值 x+y 及 y+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 0000 | 0 | 0 |
0000 0001 | 1 | 1 |
0000 0010 | 2 | 2 |
0000 0011 | 3 | 3 |
0000 0100 | 4 | 4 |
0000 0101 | 5 | 5 |
0000 0110 | 6 | 6 |
0000 0111 | 7 | 7 |
0000 1000 | 8 | 8 |
0000 1001 | 9 | 9 |
0000 1010 | 10 | A |
0000 1011 | 11 | B |
0000 1100 | 12 | C |
0000 1101 | 13 | D |
0000 1110 | 14 | E |
0000 1111 | 15 | F |
0001 0000 | 16 | 10 |
0001 0001 | 17 | 11 |
0001 0010 | 18 | 12 |
0001 0011 | 19 | 13 |
0001 0100 | 20 | 14 |
0001 0101 | 21 | 15 |
0001 0110 | 22 | 16 |
0001 0111 | 23 | 17 |
0001 1000 | 24 | 18 |
0001 1001 | 25 | 19 |
0001 1010 | 26 | 1A |
0001 1011 | 27 | 1B |
0001 1100 | 28 | 1C |
0001 1101 | 29 | 1D |
0001 1110 | 30 | 1E |
0001 1111 | 31 | 1F |
上表僅列出 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) 的概念,如果要用到複數,就直接加上虛部的 j 或 J 即可,例如
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)
沒有留言:
張貼留言