Скрипт вычисляет значения функции Аккермана, используя кэширование. Кэш вначале инициализируется, а потом происходит выполнение (ниже код).
Скрипт:
;; кэш для функции Аккермана
(defvar *akk-cache* nil)
;; счетчик рекурсивных вызовов (должен быть обнулен перед вызовом функции akk или akk-cache)
(defvar *akk-recursive-calls-counter* 0)
(defun print-akk-cache ()
  (print *akk-cache*))
(defun print-akk-calls-counter ()
  (format t "~a~%" *akk-recursive-calls-counter*))
;; эта функция инициализирует кэш указанным размером
(defun init-akk-cache (m n)
  (setf *akk-cache* nil)
  (setf *akk-cache* (make-list m))
  (let ((cache-row (make-list n :initial-element 0)))
    (dotimes (i m)
      (setf (nth i *akk-cache*) (copy-list cache-row))))
  (return-from init-akk-cache t))
;; установка значения в кэше
(defun set-akk-cache-value (m n value)
  (setf (nth n (nth m *akk-cache*)) value)
  (return-from set-akk-cache-value t))
;; получение значения из кэша					
(defun get-akk-cache-value (m n)
  (if (or (> m (length *akk-cache*)) (> n (length (nth 0 *akk-cache*))))
      (format t "FUCK!~%"))
  (let ((result (nth n (nth m *akk-cache*))))
    (return-from get-akk-cache-value result)))
;; функция Аккермана без использования кэширования
(defun akk (m n)
  (incf *akk-recursive-calls-counter*)
  (cond ((= m 0) (+ n 1))
	((= n 0) (akk (- m 1) 1))
	(t (akk (- m 1) (akk m (- n 1))))))
;; функция Аккермана с использованием кэширования
(defun akk-cache (m n)
  (incf *akk-recursive-calls-counter*)
  (if (/= (get-akk-cache-value m n) 0)
      (return-from akk-cache (get-akk-cache-value m n))
      (let ((value (cond ((= m 0) (+ n 1))
			 ((= n 0) (akk-cache (- m 1) 1))
			 (t (akk-cache (- m 1) (akk-cache m (- n 1)))))))
	(set-akk-cache-value m n value)
	(return-from akk-cache value))))
;;
(defun akk-with-calls-counting ()
  (loop for m from 0 to 3 do
       (loop for n from 0 to 14 do
	    (setf *akk-recursive-calls-counter* 0)
	    (format t "(~2a ~2a) ~12a [~a]~%" m n (akk m n) *akk-recursive-calls-counter*))))
(defun akk-cache-with-calls-counting ()
  (loop for m from 0 to 3 do
       (loop for n from 0 to 14 do
	    (setf *akk-recursive-calls-counter* 0)
	    (format t "(~2a ~2a) ~12a [~a]~%" m n (akk-cache m n) *akk-recursive-calls-counter*))))
Я работаю в Emacs/Inferior Lisp, поэтому привожу коды для запуска:
(init-akk-cache 10 1000000)
(akk-cache-with-calls-counting)
Я дошел до (3 14), дальше у меня шло переполнение стека (я 4 * не считал). Если возможно, посчитайте, пожалуйста, например, не от 0 до 3 и от 0 до 14, как сейчас, а от 0 до 5 и от 0 до 20, например. Если будет переполнение стека, то нужно увеличить размер кэша, например, на 10х10000000 и так далее.
Мой компьютер не позволяет мне такое сделать, буду очень благодарен, если поможете.



