Я читаю SICP и делать упражнения 2.5:SICP Упражнение 2.5 - селектор ведет себя непостоянно
Exercise 2.5. Показать, что мы можем представлять пары неотрицательных целых чисел используя только числа и арифметические операции, если мы представим пару
a
иb
как целое число, являющееся продуктом2^a*3^b
. Дайте соответствующие определения процедурcons
,car
, иcdr
.
Вот мое решение:
;;; Exercise 2.5
;;; ============
(define (cons x y)
(* (expt 2 x)
(expt 3 y)))
(define (car z)
; n is a power of 2, which is greater than z
(let ((n (expt 2 (ceiling (/ (log z) (log 2))))))
(/ (log (gcd z n)) (log 2))))
(define (cdr z)
; n is a power of 3, which is greater than z
(let ((n (expt 3 (ceiling (/ (log z) (log 2))))))
(/ (log (gcd z n)) (log 3))))
Мой код хорошо работает с относительно небольшими тестовыми:
(define x 12)
(define y 13)
(define z (cons x y))
(car z)
;Value: 12.
(cdr z)
;Value: 12.999999999999998
Однако он производит неправильные результаты, когда число растет больше:
(define x 12)
(define y 14)
(define z (cons x y))
(car z)
;Value: 12.
(cdr z)
;Value: 2.8927892607143724 <-- Expected 14
Я хочу знать, что не так с моя реализация. Что-то не так с алгоритмом? Идея заключается в том, что наибольший общий генератор z = 2^x * 3^y
и n
(мощность 2, которая больше z
) составляет точно 2^x
.
Если мой алгоритм верен, это непоследовательность вызвана ошибкой округления и/или переполнением?
В ваших определениях есть асимметрия, которая выглядит неправильно. Я подозреваю, что вы написали 'cdr', используя copy-and-paste. – molbdnilo
@molbdnilo Да, я так и думал, что они аналогичны. Оба 'car' и' cdr' use '(потолок (/ (log z) (log 2)))', потому что для 'z = 2^x * 3^y',' log_2 (z) 'будет больше, чем как 'x', так и' y', тогда как 'log_3 (z)' гарантированно будет больше, чем 'y'. –
@SunQingyao Я просто изменил '2' на' 3' в определении 'cdr', и я действительно получаю 14.0 вместо 2.89, поэтому он, кажется, имеет эффект. – Sylwester