編寫一個處理有理數的函數。這個是參考SICP上的一個章節來寫,其主要思想時將問題拆分成獨立的部分,然後利用這些部分構建整個過程。接下來載後面的過程中會增加正負號的判斷,並且自制打印函數,打印有理數。
(defun numer (x)
"Get the numerator of a rational number."
(car x))
(defun denom (x)
"Get the denominator of a rational number."
(cdr x))
(defun make-rat (n d)
"Make a rational number according to number and denom."
(cons n d))
;;; We define the operations of rational number. ;;;
;;; Including +, -, *, / ;;;
(defun add-rat (x y)
"Add two rational numbers."
(make-rat (+ (* (numer x) (denom y)) (* (numer y) (denom x)))
(* (denom x) (denom y))))
(defun sub-rat (x y)
"Substract rational numbers."
(make-rat (- (* (numer x) (denom y)) (* (numer y) (denom x)))
(* (denom x) (denom y))))
(defun mul-rat (x y)
"Multiply two rational numbers."
(make-rat (* (numer x) (numer y))
(* (denom x) (denom y))))
(defun div-rat (x y)
"Divide two rational numbers."
(mul-rat x (make-rat (denom y) (numer y))))
上述程序片段是簡單的實現,利用假設兩個最基本的操作,取分子和取分母,我們可以根據標準的公式來進行有理數的四則運算。
但是我們很明顯就會發現一些問題
- 有理數構建的時候分母爲0情況
- 有理數構建的時候分子和分母存在約數的情況
- 有理數的四則運算後分子和分母的約數
- 有理數的構建和運算過程中的正負號問題
現在讓我們來修復第一個問題:分母爲0的情況。
(defun make-rat (n d)
"Make a rational number according to number and denom."
(if (zerop d) (error "!!Denominator zero Wrong!!")
(cons n d)))
在上面的程序片段中,增加了關於分母是否是0的判斷,如果分母爲0,則顯示錯誤。爲了修正約數的問題,我們首先要編寫最大公約數的函數,lisp已經提供了。不過,我們嘗試自己編寫一個
(defun gcd-my (x y)
"Calculate the greatest common divisor of x and y."
(if (or (zerop x) (zerop y)) (return-from gcd-my 0)
(progn
(loop while (not (zerop (mod x y))) do
(let ((z x)) (setf x y) (setf y (mod z y)))) y)))
剩下的工作作爲練習留給大家。在這裏說一下lisp的循環。包括(dolist (var list) body), (dotimes (var times) body), (loop while () do body), (loop until () do body). loop還有一些高級用法,這裏就不展開講,大家感興趣可以去讀讀pratical common lisp。
本文完。