1. Вычисление квадратного корня с необязательным указанием точности и приближённого значения корня
;;;; Приближённое вычисление квадратного корня
;; Модуль числа
(defun abs-value (num)
(if (> num 0.0)
num
(- 0.0 num)))
;; Логическая функция, возвращающая истину,
;; если числа a и b отличаются друг от друга
;; менее, чем на precision
(defun precision-ok (a b &optional (precision 0.001))
(< (abs-value (- a b)) precision))
;; Рекурсивная функция, использующая root
;; как приближённое значение корня num.
;; Функция вызывает сама себя до тех пор,
;; пока точность результата не достигнет precision
;; По умолчанию использует 1.0 в качестве приближённого
;; значения корня и 0.001 как значение точности
(defun square-root (num &optional (root 1.0))
(if (precision-ok num (* root root))
root
(square-root num (/ (+ (/ num root) root) 2))))
;; Вычисление квадратного корня 25
(square-root 25.0)
;; Вычисление квадратного корня с указанием его
;; приближённого значения
(square-root 25.0 3.0)
Этот вариант программы плох тем, что нельзя указать при вычислении корня необходимую точность результата. Поэтому перепишем программу в следующем виде:
2. Вычисление квадратного корня с необязательным указанием точности и приближённого значения корня
;;;; Приближённое вычисление квадратного корня
;; Модуль числа
(defun abs-value (num)
(if (> num 0.0)
num
(- 0.0 num)))
;; Логическая функция, возвращающая истину,
;; если числа a и b отличаются друг от друга
;; менее, чем на precision
(defun precision-ok (a b precision)
(< (abs-value (- a b)) precision))
;; Рекурсивная функция, использующая root
;; как приближённое значение корня num.
;; Функция вызывает сама себя до тех пор,
;; пока точность результата не достигнет precision
;; По умолчанию использует 1.0 в качестве приближённого
;; значения корня и 0.001 как значение точности
(defun square-root (num &optional (root 1.0) (precision 0.001))
(if (precision-ok num (* root root) precision)
root
(square-root num (/ (+ (/ num root) root) 2) precision)))
;; Вычисление квадратного корня 25
(square-root 25.0)
;; Вычисление квадратного корня с указанием его
;; приближённого значения
(square-root 25.0 3.0)
;; Вычисление квадратного корня с указанием его
;; приближённого значения и необходимой точности
(square-root 25.0 3.0 0.00001)
По-моему гораздо удобнее. Однако если мы хотим указать точность, то необходимо также указать и приближённое значение корня. Исправим это при помощи именованных аргументов.
3. Вычисление квадратного корня с необязательным указанием точности или приближённого значения корня
;;;; Приближённое вычисление квадратного корня
;; Модуль числа
(defun abs-value (num)
(if (> num 0.0)
num
(- 0.0 num)))
;; Логическая функция, возвращающая истину,
;; если числа a и b отличаются друг от друга
;; менее, чем на precision
(defun precision-ok (a b precision)
(< (abs-value (- a b)) precision))
;; Рекурсивная функция, использующая root
;; как приближённое значение корня num.
;; Функция вызывает сама себя до тех пор,
;; пока точность результата не достигнет precision
;; По умолчанию использует 1.0 в качестве приближённого
;; значения корня и 0.001 как значение точности
(defun square-root (num &key (root 1.0) (precision 0.001))
(if (precision-ok num (* root root) precision)
root
(square-root num
:root (/ (+ (/ num root) root) 2)
:precision precision)))
;; Вычисление квадратного корня 25
(square-root 25.0)
;; Вычисление квадратного корня с указанием его
;; приближённого значения
(square-root 25.0 :root 3.0)
;; Вычисление квадратного корня с указанием
;; необходимой точности
(square-root 25.0 :precision 0.000001)
;; Вычисление квадратного корня с указанием его
;; приближённого значения и необходимой точности
(square-root 25.0 :precision 0.000001 :root 25.0)
Вот так-то. Теперь можно просто вычислить корень, можно вычислить с указанием необходимой точности, можно вычислить с указанием приближённого значения корня и, наконец, можно вычислить корень указав и необходимую точность и приближённое значение корня.
4. Вычисление квадратных корней списка чисел
Дополним программу из предыдущего пункта следующей функцией:
;;Вычисление квадратных корней списка чисел
(defun square-roots (&rest rest)
(if (eql rest nil)
nil
(cons (square-root (car rest))
(apply (function square-roots) (cdr rest)))))
;; Вычисление корней 25, 64 и 121
(square-roots 25.0 64.0 121.0)
Или можно записать немного короче, заменив оператор function на его сокращённую запись:
;; То же самое, но с использованием краткой записи
;; оператора function
(defun square-roots (&rest rest)
(if (eql rest nil)
nil
(cons (square-root (car rest))
(apply #'square-roots (cdr rest)))))
;; Вычисление корней 25, 64 и 121
(square-roots 25.0 64.0 121.0)
5. Вычисление чисел Фибоначчи
Именованные аргументы со значением по умолчанию можно использовать и для сокращения других программ. Например, уже рассмотренной ранее программы для вычисления чисел из ряда Фибоначчи:
;;;; Вычисление 20000-го числа в ряду Фибоначчи
;; Рекурсивная функция, вычисляющая число Фибоначчи
;; Вызывает себя num раз, используя a и b в качестве
;; двух предыдущих чисел в ряду
(defun fib (num &key (a 1) (b 1))
(if (eql num 1)
a
(fib (- num 1) :a b :b (+ a b))))
;; Вычисление 20000-го числа в ряду Фибоначчи
(fib 20000)
;; То же самое
(fib 20000 :a 1 :b 1)
6. Вычисление числа Фи ("Золотого сечения")
;; Вычисление числа Фи
;; Совмещённое вычисление двух последовательных
;; чисел в ряду Фибоначчи с последующим делением
;; следующего числа на предыдущее
(defun phi (&key (num 200) (a 1) (b 1))
(if (eql num 1)
(* 1.0 (/ b a))
(phi :num (- num 1) :a b :b (+ a b))))
(phi)
7. Вычисление факториала
И даже вычисление факториала, написанное в расчёте на оптимизацию хвостовой рекурсии, можно переписать в подобном же виде:
;;;; Вычисление факториала 20000
;; Вычисление факториала с применением хвостовой рекурсии
(defun fact (counter &optional (val 1))
(if (eql counter 0)
val
(fact (- counter 1) (* val counter))))
;; Вычисляем факториал 20000
(fact 20000)
Комментариев нет:
Отправить комментарий