在上一篇中介紹了一門程序設計語言必須具備的一些特性倔毙,以及Scheme語言的基本語法溅潜。這一篇用上一篇提到的平方根的問題來看看一個問題是如何被逐步分解并解決的。我們首先看下平方根的數(shù)學定義:
上面的數(shù)學公式描述了一個數(shù)的平方根所具備的性質厌衙,但并沒有告訴我們應該如何去求一個數(shù)的平方根畦木。這是數(shù)學公式和計算機程序的不同之處兜粘。對于同一個問題申窘,數(shù)學公式關心的是該問題的解所具備的性質 (what is);而計算機程序則關心應該如何去得到問題的解 (how to)孔轴。那么到底求一個數(shù)的平方根呢剃法?我們這里使用牛頓提出的無窮逼近法,這個算法思路很簡單路鹰,先假定我們要求數(shù)y的平方根x:
- 為x設定一個初始值
- 檢查x^2是否等于y贷洲,若是,則返回x, 否則將x賦值為(x+(x/y))/2
- 重復執(zhí)行第2步直到獲得解晋柱。
簡書的markdown對數(shù)學公式支持的不好优构,請見諒。有了上面的描述趣斤,我們就可以很快寫出代碼了俩块,下面我就試試使用Scheme語言來實現(xiàn)黎休。這里還是要扯點題外話浓领,我看SCIP這本書并不是為了學習Scheme語言,而是學習書中分析問題和將抽象問題的方法势腮,學習了這些之后联贩,你會恍然發(fā)現(xiàn)現(xiàn)在大多數(shù)語言或者工具的一些特性在這本書中都講到了,比如python語言捎拯、guava庫泪幌、Java8主打的lambda表達式,stream等署照。編程語言的發(fā)展有兩條截然不同的路祸泪,一條是為了適應計算機底層硬件或者說計算機體系結構發(fā)展起來的,最具代表性的就是C語言建芙;另一條路則是關心計算的本質(比較抽象没隘,這里僅是個人觀點),主要的代表就是Lisp語言禁荸,而我們這里的談到的Scheme就是Lisp語言的一種變體右蒲。但隨著技術的發(fā)展,這兩種不同類型的語言有點融合的趨勢赶熟。
在寫代碼前瑰妄,我們首先分析下這個問題,在上一篇中我們說過映砖,要解決一個問題時间坐,我們應該將問題進行分解,得到多個子問題,當子問題解決后眶诈,我們將子問題的解組合就得到了原問題的解涨醋。通過算法的描述我們可以將原有的問題分解成一些子問題:判斷數(shù)x是不是問題的解;使用算法描述中的方法將x加以改進逝撬,每次對x的改進都能夠更加接近問題的解浴骂,這就是無窮逼近。我們用Scheme語言翻譯下就是這樣:
(define (sqrt-iter x y)
(if (good-enough? x y)
x
(sqrt-iter (imporve x y) y)))
這里引入了函數(shù)sqrt-iter宪潮,它接收兩個參數(shù)x和y溯警,x表示對y的平方根的猜想,通過遞歸調(diào)用(在Scheme語言里十分重要)得到解狡相。在sqrt-iter里又引入了兩個函數(shù):good-enough?和imporve梯轻,對應著我們分析的兩個子問題。而good-enough?應該如何定義的呢尽棕?它接收兩個參數(shù)x和y喳挑,判斷x^2是否等于y。這個問題是一個比較經(jīng)典的面試題:判斷兩個浮點數(shù)是否相等滔悉。
(define (good-enough? x y)
(< (abs (- (square x) y)) 0.001))
(define (square x) (* x x))
(define (abs x)
(if (> x 0) x (- x)))
improve函數(shù)我們可以根據(jù)算法描述得到:
(define (improve x y)
(average x (/ x y)))
(define (average x y)
(/ (+ x y) 2))
這些子問題解決后伊诵,原問題就迎刃而解了:
(define (sqrt x)
(sqrt-iter 1.0 x))
這里我們假定任何數(shù)的平方根的初始值為1.0。現(xiàn)在我們再來看下sqrt函數(shù)回官,我們可以得到下面這張圖:
我們在處理原問題(sqrt)的時候曹宴,我們只需關心抽象的各個子問題,而每個子問題又可以分解為更多的子問題歉提,各個子問題可以看做是一個個的黑匣子笛坦,我們無需關心起內(nèi)部實現(xiàn)的細節(jié),我們關心其提供的功能就夠了苔巨。其實任何的程序設計都可以通過這種手段去將問題逐步分解版扩,這里的分解還需要注意一個問題,就是每個被分解后的子問題應該遵循單一職責的原理侄泽,只有這樣礁芦,解決該子問題的方法才有可能被其他的模塊進行復用。就像搭積木的例子里蔬顾,我們應該去組合一些通用形狀的積木宴偿。
好了,這一篇就簡單介紹了分析問題的方法诀豁。有疑問窄刘?請留言。另外課后的作業(yè)有一道題是之前搜狗公司的面試題舷胜,讀者可以思考下:
有inc函數(shù)和dec函數(shù)娩践,inc函數(shù)的作用是將輸入的參數(shù)加1后返回活翩,dec函數(shù)的作用是將輸入的參數(shù)減1后返回,利用inc函數(shù)和dec函數(shù)定義加法函數(shù)翻伺。
(define (+ a b) (...))