為何敲代碼,學好數學很重要?
數學是編程的靈魂所在。
作者 | Justin Meiners
譯者 | 王艷妮,責編 | 屠敏
出品 | CSDN(ID:CSDNnews)
以下為譯文:
程序員喜歡討論編程語言。除了辯論它們各自的優點外,我們還喜歡將它們整合到我們的身份認知中,甚至通過某人使用的語言來推斷這是一個怎樣的人。有些人甚至用語言決定論的一種形式爭辯,認為思維受限於可被分類的東西的。
由於我們花了很多時間來使用語言,因此想要使它們變得更好的想法是合理的。然而,這些辯論的特點表明我們認為它們代表著更多的東西。也許我們忘記了語言本身最主要的作用。編程語言是實現工具,而不是思考工具。它們是嚴格的正式的語言,以人性化的方式來給機器下指令。相反,思想最好通過一種自由而靈活的媒介來表達。
用數學思考
數千年來,被高效地用於計算方面思考的自然語言就是數學。大多數人並不認為數學是自由的或靈活的。他們在學校看到可怕的符號和對解題步驟生硬記憶的經歷與自由和靈活的數學精神恰恰相反。我希望本文的讀者在數學方面有更好的經歷,比如在離散數學或線性代數課程中; 那種涉及構建清晰的定義和演繹,並用符號寫成散文(推理步驟)的經歷(大多數符號甚至直到16世紀才被發明)。
數學允許你推理邏輯結構,而不受其他約束的影響。這也是編程所需要的:創建邏輯系統來解決問題。我們來看一下編程的基本模式:
找出問題所在
設計演算法和數據結構來解決它
實現和測試
在實踐中,工作往往組織得不是那麼好,因為步驟之間存在相互作用。你可以編寫代碼來通知別人設計方面的問題。可即便如此,上面這個基本模式也一遍又一遍地在實踐中重現。
請注意,步驟1和2是佔用我們大部分時間,能力和精力的步驟。同時,這些步驟並不適合編程語言。這並不能阻止程序員嘗試在他們的編輯器中解決它們,但他們最終會得到一些混亂,緩慢或解決了錯的問題的代碼。並不是編程語言還不夠好。沒有哪一種正式語言在這方面擅長。我們的大腦就不是那麼思考問題的。當問題變得困難時,我們繪製圖表並與同事們討論。
理想情況下,首先解決步驟1和2,然後才使用編程語言來解決步驟3。這在轉換實現過程中有額外的好處。有了數學解決方案,你就可以專註於選擇最佳的表示和實現方式,編寫更好的代碼,了解最終目標將是什麼。
實現問題
為什麼編程語言作為思維工具是繁瑣的?一個原因是編寫代碼與實現密不可分。實現問題對於給計算機下指令是必要的,並且值得做好,但它們也分散了在要解決的問題方面的注意力。想想如果要編寫一個簡單的函數,所有的注意事項:
我應該提供什麼輸入?
它們應該被命名為什麼?
它們應該是什麼類型的?(即使動態類型語言也必須考慮類型,它是隱含的而已。)
我應該通過值還是通過引用來傳遞它們?
我應該把這個函數放在什麼文件中?
結果是否應該重複使用,或者它是否足夠快以便每次重新計算?
這個列表還可以繼續下去。關鍵是這些考慮因素與函數的作用無關。它們會分散人們對該函數試圖解決的問題本身的注意力。
許多語言旨在隱藏諸如此類的細節,這對於普通的日常任務尤其有用。但是,它們無法超越其作為實現工具的角色。SQL很容易被認為是這方面最成功的例子之一,但它最終關注的還是表,行,下標和類型等實現方面的問題。正因為如此,程序員仍然在編寫一堆JOIN之前,以隨意的方式設計一些複雜的查詢,比如一些他們想要「獲取」的東西。
不靈活的抽象
編程語言的另一個限制是它們是糟糕的抽象工具。通常,當我們討論工程中的抽象時,我們的意思是隱藏實現細節。一個複雜的操作或過程被打包成一個「黑盒」,其內容隱藏,並且暴露出明確定義的輸入和輸出。伴隨著這個盒子的是一個關於它的功能的虛構故事,這很容易理解。
黑盒對於大型系統的工程設計至關重要,因為細節過多,對人腦來說理解起來壓力山大。它們也有許多眾所周知的局限性。黑盒泄漏是因為其簡要的說明無法完全表述清楚其具體行為。不透明的界面引入了低效率,例如重複和分散設計。
最重要的是對解決問題來說,黑盒很僵硬。它們呈現出固定的抽象層級,這個層級可能對問題來說級別太高或太低。從理論上講,你可以隨時查看黑盒內部,但在代碼中,任何時候的抽象級別都是固定的。它們也只提供了一種抽象視角。一個高級Web伺服器可以提供用於服務JSON的極好的介面,但是如果你想要將其用於提供不完整數據流的介面(例如來自程序的輸出)那它表現就很差了。
相比之下,數學中的抽象一詞與隱藏信息完全不同。這裡,抽象意味著提取與特定上下文相關的某些事物的基本特徵或特徵。與黑盒不同,這不會隱藏任何信息。它們不會以同樣的方式泄漏。我們鼓勵你調整到正確的抽象級別,並在不同角度之間快速跳轉:
這個問題最好用表來表示嗎?或者,一個函數?
我可以將整個系統視為一個函數嗎?
我可以將這些東西作為一個整體處理嗎?
我應該看整個系統還是單個部分?
我應該做出什麼假設?我應該讓它們更強還是更弱?
只需看看一個函數的多種表示方法:
數學的主要分支代表了常用的抽象:
幾何圖形從世界中的物體中(或轉換不變數,取決於想要獲得的宇宙)抽象出基本形狀。
拓撲從其形狀中提取表面特徵。
群論將二元運算抽象為關於它們如何組合和反轉的屬性。
但是,並不僅限於這幾個領域。你可以選出對某個問題很重要的屬性,並忽略其他。文章最後的示例項目顯示了如何完成此操作。
編程語言非常適合構建黑盒; 它們提供了函數,類和模塊,所有這些都有助於將代碼包裝到漂亮的介面中。但是,在嘗試解決問題和設計解決方案時,你真正想要的是數學那樣的抽象。如果你試著在鍵盤邊上思考,可用的黑盒會扭曲你的視線。
問題表徵
正如編程語言的抽象能力有限一樣,它們在表示數據的方式上也受到限制。實現演算法或數據結構的行為只是選擇一個能表示它的許多可能的方式之一。通常,在你了解所需內容之前,這還不是一個你想現在就做出的決定。
例如,圖(頂點和邊的集合)出現在許多編程問題中,例如互聯網網路,尋路和社交網路。儘管定義簡單,但選擇如何表示它們很難並且這取決於它們的使用情境:
與定義最匹配的那個:
vertices:vector <NodeData> edges:vector <pair <Int,Int >>如果你只關心連接問題,可以刪除頂點。
如果要快速遍歷節點的鄰接節點,那麼你可能需要一個節點結構:
Node{id:Int,neighbors:vector <Node *>}
你可以使用鄰接矩陣。每行存儲特定節點的鄰接節點:
connectivity:vector <vector <int >>
尋路演算法通常在單元板上隱式地處理圖:
walls:vector <vector <bool >>
在對等網路中,每台計算機都是一個頂點,每個插槽都是一個邊。整個圖表甚至無法從一台機器訪問!
數學允許你對圖本身進行推理,解決問題,然後選擇合適的表達方式。如果你使用編程語言進行思考,則不能延遲此決定,因為你的第一行代碼就是為了特定的表達而存在的。
請注意,圖的表示太多樣化,無法限於單一種類的介面,類型類(tpyeclass)甚至程序。因此,創建一個可完全復用的庫是不切實際的。它只能在幾種類型上工作,或者強制所有圖使用不恰當的表示。但這並不意味著庫沒用。類似的表示會重複出現(比如std :: vector),但你沒法寫一個能一勞永逸地解決所有圖形問題的庫。
一些現代編程語言試圖提供更多的數學抽象工具。例如,Haskell有Ring和Group類型類(typeclass)。然而,表示問題表明這些特徵肯定不如它們的理論靈感有用。編寫一個僅依賴於關聯屬性並且就那樣存檔的演算法是明智的。這就是用數學語言思考。但是,實際上,這隻能適度地處理相似類型的小家族。考慮幾種類型的簡單通用是合適的。
作為必然結果,編程語言應該主要將注意力放在如何做好一個有用的實現工具,而不是思考工具上。C在很大程度上做到了這一點。C#的非同步和等待等現代語言功能為實現並發程序提供了很大的改進。
示例項目
那麼用數學思考是什麼樣的一個過程呢?最近,我在工作中研究了一個API,它為商家的加密貨幣定價。它考慮了最近的價格變動,並建議商家在動蕩時期收取更高的價格。
雖然我們在理論上做了一些功課,但我們想通過實證檢驗它以了解它在各種市場條件下的表現。為此,我設計了一個機器人來模擬與我們的API開展業務的商家,以了解它的表現。
BTC / USD(1天)
預備步驟:
定義:匯率r(t)是法定/加密貨幣的市場匯率。
定義:商家費率r"(t)是商家被建議向客戶收費的修改後的匯率。
定義:當客戶購買商品時,我們稱該行為是「購買」。購買包括法定價格和時間。p =(f,t)。
定理:通過應用修改的匯率t(p)= p(1)/ r"(p(2))找到購買的加密量。
證明:p(1)/ r"(p(2))= fiat /(fiat / crypto)= fiat * crypto / fiat = crypto
定義:當商家出售他們的加密資產時,我們將該事件稱為銷售。銷售包括加密金額和時間戳。s =(c,t)。
定理:通過將匯率應用於銷售g(s)= s(1)* r(s(2))來找到商家從銷售中獲得的法定金額。
證明:s(1)* r(s(2))= 加密*(法定/ 加密)=法定
定義:一組購買和銷售的餘額是所有購買加密金額和所有銷售加密金額之間的差額。b(P,S)=從t到p(p_i)的i到N之和 - 從j到M的s_j(1)之和
請注意,b(P,S)> = 0必須始終成立。
定義:一組購買和銷售的收益是銷售法定金額和購買法定金額之間的差額。e(P,S)=(s_j(1))從j到M的總和- p_i(1)從i到N的和> = 0。
目的
定義:如果大多數典型的購買和銷售收入都是非負的,我們說商家利率是有利的。
r"(t) is favorable iff e(P, S) >= 0.
在一個有利的案例中,商人通過接受加密並沒有失去任何法定貨幣。
「大多數」和「典型」的兩個要求將不會被嚴格定義。
作為典型的一部分,我們可以假設商家會及時出售他們的加密資產。因此,假設s_i(2) - s_j(2)<W在i,j屬於{1 .. M}範圍內時成立,某些約束W.購買金額應隨機分布在商業行為完成的合理範圍內。也許10-100美元。
機器人的目標是驗證r"(t)是有利的。
請注意,此定義只是質量的一種衡量標準。也許抵制最壞的情況比有利更重要。在這種情況下,我們會擔心可能會進行一組收益非常低的購買。
演算法
重複多次:
隨機選擇時間範圍[t0,t1]。
在[t0,t1]內的隨機時間生成一組購買。價格應該在典型價格的[p0,p1]範圍內。
在[t0,t1]內以均勻間隔時間(可能具有輕微隨機雜訊)生成一組銷售額。每次銷售應該是當時的全部餘額。
計算這些集合的收入。
記錄收入。
後:
報告有多少收入為負數,有多少為非負數。顯示每個的百分比。
確定最低和最高收入並報告。
總結
當你閱讀這個例子時,我認為你的傾向可能是認為它的陳述是顯而易見的。當然,這些步驟都不是很難。然而,令我驚訝的是,我的許多假設得到了糾正,選擇有利結果的客觀定義是多麼困難。這個過程讓我意識到一些如果我從簡單編寫代碼開始的話,就壓根不會考慮的假設。也許最大的好處是,在編寫之後,我能夠與同事一起快速審查它並進行簡單的更正,但在代碼中很難改變。
我希望用數學語言思考會給你的項目帶來類似的好處!請注意,此示例只是一種利用數學思維的方式。我建議讀Leslie Lamport,Udi Manber和Alex Stepanov等等其他人的想法。
原文:https://justinmeiners.github.io/think-in-math/
本文為 CSDN 翻譯,轉載請註明來源出處。
下面給大家推薦 CSDN 的好朋友——程序人生。
為什麼推薦程序人生?
程序人生聚集百萬程序員,在這裡你可以笑談開發軼事,吐槽百味的程序人生。
無論是從行業熱點到經驗解析,從職場困惑到風口趨勢,還有程序員不為人知的秘密,我們將為你一一揭曉。
龍泉寺的IT高僧是用哪種編程語言呢?Java ? Python?這篇10W+文章告訴你↓↓↓
程序員下班時,為啥電腦不關只揣了手機就走啦??這篇9W+文章過於真相了↓↓↓
調查上萬名程序員,竟然發現女程序員比男程序員更懂 Java?怎麼回事啊??↓↓↓
※如果微軟開發了 Android,會有何不同?
※剛剛!為吊打穀歌,微軟砸10億美元布局AI,網友炸了!發帖上熱門……
TAG:CSDN |