Я читаю SICP и делаю упражнение 2.5:
Упражнение 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
(степень двойки, которая больше z
) - это ровно 2 ^ x
.
Если мой алгоритм верен, вызвано ли это несоответствие ошибкой округления и / или переполнением?
cdr
методом копирования и вставки. - person molbdnilo   schedule 18.01.2017car
, иcdr
используют(ceiling (/ (log z) (log 2)))
, потому что дляz=2^x*3^y
log_2(z)
будет больше, чемx
иy
, аlog_3(z)
только гарантированно будет большеy
. - person nalzok   schedule 18.01.20172
на3
в определенииcdr
, и на самом деле я получаю 14.0 вместо 2.89, так что, похоже, это имеет эффект. - person Sylwester   schedule 19.01.2017(car (cons 31 37))
не возвращает 31.0. - person Will Ness   schedule 20.01.2017