Общие делители чисел - Lisp
Формулировка задачи:
Помогите пожалуйста,нужно найти общие делители двух чисел.Например 64 и 32.Общими делителями будут 1 2 4 8 16 32.Но в ответе нужно проверить: если следующее число делится на предыдущее без остатка, то его не выводим.
Получаемый ответ: 1 2
Решение задачи: «Общие делители чисел»
textual
Листинг программы
;; НОД (defun gcd (n m) (cond ((> n m) (gcd m n)) ((zerop n) m) (t (gcd n (- m n))))) ;; Реверс списка (defun reverse (x &optional (r nil)) (cond ((null x) r) (t (reverse (cdr x) (cons (car x) r))))) ==> reverse (reverse '(1 2 3)) ==> (3 2 1) ;; Решение (defun lst-comm-div (n m &optional (g (gcd n m)) (r (list 1)) (i 2)) (cond ((>= i g) (reverse r)) ((and (zerop (mod n i)) (zerop (mod m i))) (cond ((or (= 1 (car r)) (/= 0 (rem i (car r)))) (lst-comm-div n m g (cons i r) (+ i 1))) (t (lst-comm-div n m g r (+ i 1))))) (t (lst-comm-div n m g r (+ i 1))))) ==> lst-comm-div (lst-comm-div 45 15) ==> (1 3 5)
Объяснение кода листинга программы
Код решает задачу поиска общих делителей двух чисел.
- Начиная с функции
gcd
, которая вычисляет наибольший общий делитель (НОД) двух чиселn
иm
. Используется рекурсивный алгоритм. Еслиn
большеm
, то функция вызывает саму себя, но уже с аргументамиm
иn
. Еслиn
равно нулю, то возвращаетсяm
. Иначе, функция продолжает поиск НОДа, вычитая изn
частное от деления наm
. - Функция
reverse
реверсирует список. Если список пуст, то возвращаетсяnil
. Иначе, функция вызывает саму себя, но уже с аргументомcdr
от первого элемента списка и списком, в который добавляется первый элемент списка (который удаляется из списка), а также возвращаемым значением. - Функция
lst-comm-div
находит общие делители чиселn
иm
. Изначально, список общих делителейr
инициализируется списком[1]
, а переменнаяi
равна2
. Если индексi
больше или равен значению, которое хранится в переменнойg
(которая инициализируется значением, равным НОДn
иm
), то возвращается списокr
, перевёрнутый с помощью функцииreverse
. Иначе, если остаток от деленияn
наi
равен нулю и остаток от деленияm
наi
также равен нулю, то текущий элемент спискаr
(к которому добавляетсяi
) не является общим делителем, и мы переходим к следующему элементу списка (увеличивая значениеi
на1
). Если текущий элемент спискаr
делится наi
без остатка, то мы переходим к следующему элементу списка (увеличивая значениеi
на1
). Если текущий элемент спискаr
не делится наi
без остатка, то мы переходим к следующему элементу списка (увеличивая значениеi
на1
). Если текущий элемент спискаr
равенnil
, то мы переходим к следующему элементу списка (увеличивая значениеi
на1
). Если текущий элемент спискаr
не равенnil
, то мы переходим к следующему элементу списка (увеличивая значениеi
на1
). Если мы дошли до конца спискаr
, то возвращается значениеnil
.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д