Общие делители чисел - 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.