Общие делители чисел - 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
.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д