編程需要知道多少數(shù)學(xué)知識?
下面是我在reddit的子論壇 r/learnprogramming 看到的幾個(gè)帖子:
● “要成為一個(gè)優(yōu)秀的程序員需要學(xué)習(xí)多少數(shù)學(xué)?”
● “我應(yīng)該重新學(xué)習(xí)數(shù)學(xué)嗎?”
● “這可能是我提問過的最愚蠢的一個(gè)問題。成為一個(gè)優(yōu)秀的程序員究竟需要學(xué)習(xí)多少數(shù)學(xué)?”
數(shù)學(xué)和編程有一種容易讓人誤解的聯(lián)系。許多人認(rèn)為在開始學(xué)習(xí)編程之前必須對數(shù)學(xué)很在行或者數(shù)學(xué)分?jǐn)?shù)很高。但一個(gè)人為了編程的話,需要學(xué)習(xí)多少數(shù)學(xué)呢?
實(shí)際上不需要很多。這篇文章中我會深入探討編程中所需要的數(shù)學(xué)知識。你可能已經(jīng)都知道了。
對于基本的編程,你需要知道下面的:
● 加減乘除 — 實(shí)際上,電腦會幫你作加減乘除運(yùn)算。你僅需要知道什么時(shí)候運(yùn)用它們。
● 模運(yùn)算 — 模運(yùn)算是用來計(jì)算余數(shù),它的符號通常用%百分號來表示。所以23除以7等于3,余數(shù)是2。23 mod 7 = 2。
● 判斷是奇數(shù)還是偶數(shù)的模運(yùn)算 — 如果你想知道一個(gè)數(shù)是奇數(shù)還是偶數(shù),用它mod 2來作模運(yùn)算。如果結(jié)果是0,它就是偶數(shù)。如果結(jié)果是1,就是奇數(shù)。23 mod 2等于1,所以23是奇數(shù),24 mod 2等于0,24是偶數(shù)。
● 對一個(gè)數(shù)作百分?jǐn)?shù)運(yùn)算,就是用這個(gè)數(shù)來乘以一個(gè)百分?jǐn)?shù)。譬如你要得到279的54%,就是用0。54*279。這就意味著為什么1.0等于100%,0.0等于0%。
● 知道負(fù)數(shù)是什么。負(fù)數(shù)乘以負(fù)數(shù)等于正數(shù)。負(fù)數(shù)乘以正數(shù)等于負(fù)數(shù)。就這么簡單。
● 知道卡迪爾坐標(biāo)系統(tǒng)。在編程中,(0,0)代表屏幕左上角,Y坐標(biāo)的正軸往下。
● 知道勾股定律,因?yàn)樗怯脕碛?jì)算笛卡爾坐標(biāo)中兩點(diǎn)之間的距離的。勾股定律a^2 + b^2 = c^2。(x1, y1)和(x2, y2)兩點(diǎn)之間的距離等于( (x1 – x2)^2 + (y1 – y2)^2 )。
● 知道十進(jìn)制、二進(jìn)制、十六進(jìn)制。十進(jìn)制就是我們通常用的十個(gè)數(shù):0-9。通常認(rèn)為這個(gè)十進(jìn)制系統(tǒng)是人類發(fā)明的,因?yàn)槲覀冇惺畟€(gè)手指。
電腦采用二進(jìn)制數(shù)據(jù),只有兩個(gè)數(shù)字:0和1。這是因?yàn)槲覀冇秒娮釉順?gòu)建的電腦,讓電腦只識別兩種狀態(tài)更便宜些(一種代表0,另一種代表1)。
數(shù)是一樣的,但是在不同的進(jìn)制系統(tǒng)里的表現(xiàn)形式不同,因?yàn)椴煌M(jìn)制包含的數(shù)的個(gè)數(shù)不同。十六進(jìn)制比十進(jìn)制多六個(gè)數(shù)字,所以我們用A-F表示超過9的數(shù)。能夠表現(xiàn)這些進(jìn)制系統(tǒng)的最簡單方法就是用一個(gè)計(jì)數(shù)器(odometer)。下面三種不同的計(jì)數(shù)器顯示的是同一個(gè)數(shù),但在不同的進(jìn)制系統(tǒng)中的形式不同:
在新窗口中查看計(jì)數(shù)器頁面
你甚至不需要知道怎么從一個(gè)進(jìn)制系統(tǒng)轉(zhuǎn)換成另一個(gè)系統(tǒng)。每種編程語言都有幫你轉(zhuǎn)換的函數(shù)。
(提示一下,十六進(jìn)制的使用是因?yàn)橐粋€(gè)十六進(jìn)制的數(shù)可以表示四個(gè)二進(jìn)制的數(shù)。因?yàn)槭M(jìn)制中的3和二進(jìn)制中的0011對應(yīng),十六進(jìn)制的A和二進(jìn)制的1010對應(yīng),所以十六進(jìn)制中的3A(十進(jìn)制的58)可以寫成二進(jìn)制的00111010。十六進(jìn)制在編程中的使用是因?yàn)樗菍ΧM(jìn)制的簡化。沒人喜歡寫出的數(shù)全是0和1。)
就是這么多了。除了進(jìn)制系統(tǒng)以外,你可以已經(jīng)知道編程所需的數(shù)學(xué)知識了。雖然普遍認(rèn)為編程需要學(xué)習(xí)許多數(shù)學(xué),但實(shí)際上并不需要那么多。你可能為了編寫一個(gè)程序,譬如說地震模擬器,而需要學(xué)習(xí)數(shù)學(xué)。其實(shí)你更需要學(xué)習(xí)地震的數(shù)學(xué),而不是因?yàn)橐帉懙卣鹉M器而學(xué)習(xí)數(shù)學(xué)。
某些編程領(lǐng)域中更為高級的數(shù)學(xué)
有一些領(lǐng)域中需要更多的數(shù)學(xué)知識(但95%的軟件中,你都不需要知道它們。)
● 3D游戲和3D繪圖 — 3D通常需要涉及三角函數(shù)和線性代數(shù)(用矩陣來解決問題的數(shù)學(xué))。當(dāng)然,有許多3D圖形庫已經(jīng)實(shí)現(xiàn)了這些數(shù)學(xué)編程,你不需要知道這些數(shù)學(xué)。
● 2D物理(譬如憤怒的小鳥)和3D物理(譬如許多流行的3D游戲) — 為了寫涉及到物理的編程,你需要學(xué)習(xí)一些物理方程和公式(尤其是力學(xué),如彈力,重力,球滾下斜坡等物理。)然而,已經(jīng)有一些物理引擎和軟件庫幫你實(shí)現(xiàn)了,所以你也不需要知道游戲(如憤怒的小鳥)中的物理公式。
● 加密學(xué) — 事實(shí)上我指的是RSA。你需要知道質(zhì)數(shù)的有關(guān)知識,以及如何求最大公約數(shù)(其實(shí)是個(gè)非常簡單的算法,還有許多編程語言中都有g(shù)cd()函數(shù),幫你求解最大公約數(shù))其他的編碼大部分就是將數(shù)據(jù)按照某種步驟挪動。舉個(gè)例子,下面的flash就是AES“Rijndael”編碼的步驟。所有的步驟包含用一些數(shù)減去另一些數(shù),將行向上移,將列數(shù)字打亂,再作簡單的加法運(yùn)算。
如果你要寫你自己的加密算法(通常不需要你做,因?yàn)橐呀?jīng)有許多很好的工具了,并且如果你不是加密學(xué)的專家的話,你的程序也許會很容易被破解。)如果你僅僅想加密一些數(shù)據(jù)的話,已經(jīng)有許多加密和解密的軟件庫了。
所以就算是以上的情況,你也不需要真正的知道3D圖像,物理或者加密的數(shù)學(xué)。你只需要學(xué)習(xí)運(yùn)用軟件庫就行了。
編程需要學(xué)習(xí)什么?
你需要學(xué)習(xí)的是如何建模和設(shè)計(jì)算法。這意味著,如何將真實(shí)世界的運(yùn)算或者數(shù)據(jù)處理抽象出來,寫出代碼,讓計(jì)算機(jī)來幫你運(yùn)算。例如,在游戲“龍與地下城”(Dungeons and Dragons)中,角色和怪獸都有許多不同的戰(zhàn)斗統(tǒng)計(jì)值:
● 血點(diǎn)(Hit points)是一個(gè)人死前所能經(jīng)受的傷害值。越高的血點(diǎn)就意味著可以經(jīng)受更多的傷害。
● 防御等級(armor class)是對你的武器防御能力的量度。防御值越低,武器的防御能力越高。
● THAC0(讀作“thay-co”,“To Hit Armor Class 0”),是對一個(gè)人進(jìn)行有效攻擊的能力的測量。THAC0值越低,攻擊越準(zhǔn)。
● 武器的攻擊力用類似1d6+2來表示,它表示搖一個(gè)六面骰得到的值,然后再加2。2d4就是搖2個(gè)4面骰,然后將它們相加。(“龍與地下城”采用的是4,6,8,10,12和20面骰。)
要看攻擊者打防御者,讓攻擊者搖動一個(gè)20面骰。如果這個(gè)數(shù)字大于或等于攻擊者的THAC0減去防御者的防御能力,那么這個(gè)攻擊就成功,防御者將受到傷害。不然,防御者就阻擊了這個(gè)攻擊,并且不費(fèi)血。
我們假設(shè)兩個(gè)人物,Alice和Bob,她們具有以下值:
● Alice: HP 14, AC 5, THAC0 18, DAMAGE 1d6
● Bob: HP 12, AC 7, THAC0 16, DAMAGE 2d4
所以Alice有更多的血點(diǎn)和防御力(記住,AC越低越好)。但是Bob更可能成功擊中對方(記住,THAC0越低越好),并造成更多的傷害。我們說Bob的攻擊力更強(qiáng)是因?yàn)?d4可以造成2-8點(diǎn)傷害,而Alice的1d6只能造成1-6點(diǎn)傷害。(如果你懂統(tǒng)計(jì)學(xué),你可以計(jì)算出Bob的期望傷害值是5,比Alice的3。5要高。)
你會打賭Alice或者Bob會贏得比賽對嗎?很難講誰會贏,他們看起來勢均力敵。盡管可能你的統(tǒng)計(jì)學(xué)學(xué)得很好,但做這個(gè)計(jì)算將會十分頭疼。編寫“龍與地下城”的程序(模擬戰(zhàn)斗過程),你甚至不需要知道統(tǒng)計(jì)學(xué)。僅僅需要運(yùn)行幾百次或者幾千次戰(zhàn)斗,看看誰贏得更多。
下面是用Python寫的程序:(下載代碼)
- import random, copy
- NUM_FIGHTS = 1
- VERBOSE = True
- # Lower thac0 and lower ac values are better. Higher damage & hp values are better.
- aliceTemplate = {'name': 'Alice', 'hp': 14, 'ac': 5, 'thac0': 18, 'dmgnum': 1, 'dmgsize':6, 'dmgmod': 0}
- bobTemplate = {'name': 'Bob', 'hp': 12, 'ac': 7, 'thac0': 16, 'dmgnum': 2, 'dmgsize':4, 'dmgmod': 0}
- def display(s):
- if VERBOSE:
- print(s)
- def attack(attacker, defender):
- if random.randint(1, 20) >= attacker['thac0'] - defender['ac']:
- damage = 0
- for i in range(attacker['dmgnum']):
- damage += random.randint(1, attacker['dmgsize'])
- damage += attacker['dmgmod']
- display('%s (%s hp) hits %s (%s hp) for %s points of damage. %s is reduced to %s hp.' % (attacker['name'], attacker['hp'], defender['name'], defender['hp'], damage, defender['name'], defender['hp'] - damage))
- defender['hp'] -= damage
- else:
- display('%s misses %s.' % (attacker['name'], defender['name']))
- aliceWins = 0
- bobWins = 0
- for i in range(NUM_FIGHTS):
- display('======================')
- display('Start of combat #%s' % (i+1))
- alice = copy.deepcopy(aliceTemplate)
- bob = copy.deepcopy(bobTemplate)
- while True:
- attack(alice, bob)
- if bob['hp'] <= 0:
- break
- attack(bob, alice)
- if alice['hp'] <= 0:
- break
- if alice['hp'] <= 0:
- display('Alice has died.')
- bobWins += 1
- if bob['hp'] <= 0:
- display('Bob has died.')
- aliceWins += 1
- print()
- print('Alice won %s (%s%%) fights. Bob won %s (%s%%) fights.' % (aliceWins, round(aliceWins / NUM_FIGHTS * 100, 2), bobWins, round(bobWins / NUM_FIGHTS * 100, 2)))
當(dāng)運(yùn)行這個(gè)程序時(shí),你會看到:
- Start of combat #1
- Alice misses Bob.
- Bob (12 hp) hits Alice (14 hp) for 6 points of damage. Alice is reduced to 8 hp.
- Alice misses Bob.
- Bob misses Alice.
- Alice misses Bob.
- Bob misses Alice.
- Alice misses Bob.
- Bob misses Alice.
- Alice (8 hp) hits Bob (12 hp) for 5 points of damage. Bob is reduced to 7 hp.
- Bob misses Alice.
- Alice misses Bob.
- Bob misses Alice.
- Alice misses Bob.
- Bob (7 hp) hits Alice (8 hp) for 2 points of damage. Alice is reduced to 6 hp.
- Alice (6 hp) hits Bob (7 hp) for 6 points of damage. Bob is reduced to 1 hp.
- Bob misses Alice.
- Alice (6 hp) hits Bob (1 hp) for 1 points of damage. Bob is reduced to 0 hp.
- Bob has died.
- Alice won 1 (100.0%) fights. Bob won 0 (0.0%) fights.
但是可能Alice正好在某一次戰(zhàn)斗中很幸運(yùn)。讓我們關(guān)掉輸出再重新運(yùn)行程序(在屏幕輸出比運(yùn)行程序更耗時(shí)間),當(dāng)戰(zhàn)斗次數(shù)達(dá)到30,000次時(shí)(將NUM_FIGHTS改成30000,VERBOSE變量變成False):
- Alice 贏得12909 (43.03%)次戰(zhàn)斗. Bob贏得17091 (56.97%)戰(zhàn)斗。
所以我們看到使用上面的數(shù)值,Bob稍稍占先。電腦進(jìn)行了30,000次戰(zhàn)斗模擬。如果我們用筆和紙還有骰來進(jìn)行30000次戰(zhàn)斗模擬的話,可能需要幾個(gè)月來算出結(jié)果,而我的筆記本僅用了8秒。
那么如果Alice的血點(diǎn)從14增加到20呢。誰會贏呢?
- Alice贏得19438 (64.79%)次戰(zhàn)斗. Bob贏得10562 (35.21%)次戰(zhàn)斗.
我們看到給Alice增加6點(diǎn)血點(diǎn),結(jié)果倒過來了,Alice占先了。那么如果Alice的血點(diǎn)只是增加到16呢?
- Alice贏得15176 (50.59%)次戰(zhàn)斗啊. Bob贏得14824 (49.41%)次戰(zhàn)斗.
所以僅僅增加2個(gè)血點(diǎn),就已經(jīng)足夠扳回Bob更強(qiáng)攻擊力的勝算。
來看這個(gè)程序,它只用了加減乘除來計(jì)算一個(gè)百分比。甚至在更復(fù)雜的程序中,需要表示magic spells,治愈部位,多次攻擊,在戰(zhàn)斗中切換武器等不同效果時(shí),我們也不需要知道更多的數(shù)學(xué)了。
當(dāng)然,去學(xué)更多的數(shù)學(xué)吧??梢宰屇愠蔀楦錾某绦騿T。但是為了學(xué)習(xí)編程需要多少數(shù)學(xué)?真的非常少。
更新:我想我應(yīng)該在基本知識點(diǎn)中增加基本代數(shù),但僅僅需要知道的如 如果X * 3 = 12,知道X等于4。
英文原文:Al Sweigart