Lisp实现有理数的运算

时间:2022-10-08 10:19:25

  编写一个处理有理数的函数。这个是参考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))))
  上述程序片段是简单的实现,利用假设两个最基本的操作,取分子和取分母,我们可以根据标准的公式来进行有理数的四则运算。

   但是我们很明显就会发现一些问题

  1. 有理数构建的时候分母为0情况
  2. 有理数构建的时候分子和分母存在约数的情况
  3. 有理数的四则运算后分子和分母的约数
  4. 有理数的构建和运算过程中的正负号问题

  现在让我们来修复第一个问题:分母为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。

  本文完。