SICP练习2.5 - 选择器表现不定

时间:2017-01-17 14:08:54

标签: algorithm floating-point scheme numerical-methods sicp

我正在阅读SICP并进行练习2.5:

  

Exercise 2.5.表明我们可以代表非负的对   如果我们代表,只使用数字和算术运算的整数   对ab作为产品2^a*3^b的整数。   给出相应的程序定义conscar,   和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 ^ yn(2的幂,大于z)的最大共同主管正是2 ^ x

如果我的算法是正确的,这是由舍入错误和/或溢出引起的不一致吗?

1 个答案:

答案 0 :(得分:2)

一种解决方案是避免使用浮点数。

考虑max-power-dividing找到最大指数k,使p^k除以n

(define (max-power-dividing p n)
  (if (zero? (remainder n p))
      (+ 1 (max-power-dividing p (/ n p)))
      0))

然后我们可以写:

(define (car z) (max-power-dividing 2 z))
(define (cdr z) (max-power-dividing 3 z))

据我所知,你的解决方案使用了正确的想法,但浮点计算会破坏大数。