SICP 1.45-为什么这两个高阶函数不相等?

时间:2018-12-25 22:12:10

标签: scheme lisp higher-order-functions sicp

我正在研究[SICP] [1]中的练习,想知道是否有人可以解释这两个看似等效的函数之间的区别,这些函数给出不同的结果!这是因为舍入吗?我认为功能的顺序在这里不重要,但是某种程度上呢?有人可以解释这里发生的事情以及为什么与众不同吗?

详细信息:

  

练习1.45 :..发现找到y => x/y的固定点不会   收敛,并且可以通过平均阻尼来固定。相同   该方法适用于寻找立方根作为定点   平均衰减的y => x/y^2。不幸的是,该过程不起作用   对于第四根-单次平均阻尼不足以使   y => x/y^3的定点搜索收敛。

     

另一方面,如果我们   平均阻尼两次(即使用   y => x/y^3)定点搜索确实会收敛。做一些实验   确定计算第n个根所需的平均阻尼数   作为基于y => x/y^(n-1)的重复平均阻尼的定点搜索。

     

使用它来实现一个简单的过程来计算根   使用fixed-pointaverage-damprepeated过程    1.43 。假设您需要的任何算术运算是   可作为基元使用。

我的答案(注意顺序为repeataverage-damping

(define (nth-root-me x n num-repetitions)
  (fixed-point (repeat (average-damping (lambda (y)
                                           (/ x (expt y (- n 1)))))
                       num-repetitions)
               1.0))

我看到了一个替代的Web解决方案,其中直接在repeat上调用average damp,然后使用参数调用该函数

(define (nth-root-web-solution x n num-repetitions)
      (fixed-point
         ((repeat average-damping num-repetition)
          (lambda (y) (/ x (expt y (- n 1)))))
         1.0))

现在同时调用这两种方法,答案似乎有所不同,我不明白为什么!我的理解是函数的顺序不应该影响输出(它们是关联权吗?),但显然是这样!

> (nth-root-me 10000 4 2)
> 
> 10.050110705350287
> 
> (nth-root-web-solution 10000 4 2)
> 
> 10.0

我做了更多的测试,而且总是这样,我的答案很接近,但是另一个答案几乎总是很接近!有人可以解释发生了什么吗?为什么这些不是等效的?我的猜测是这些函数的调用顺序很混乱,但它们似乎与我联系在一起。

例如:

(repeat (average-damping (lambda (y) (/ x (expt y (- n 1)))))
         num-repetitions)

vs

((repeat average-damping num-repetition)
 (lambda (y) (/ x (expt y (- n 1)))))

其他助手功能:

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2))
       tolerance))
  (let ((next-guess (f first-guess)))
    (if (close-enough? next-guess first-guess)
        next-guess
        (fixed-point f next-guess))))

(define (average-damping f) 
  (lambda (x) (average x (f x))))

(define (repeat f k)
  (define (repeat-helper f k acc)
    (if (<= k 1)
        acc
           ;; compose the original function with the modified one
        (repeat-helper f (- k 1) (compose f acc)))) 
  (repeat-helper f k f))

(define (compose f g)
  (lambda (x)
    (f (g x))))

2 个答案:

答案 0 :(得分:4)

您在问为什么“两个看似等效的函数”产生不同的结果,但实际上这两个函数却有很大差异。

让我们尝试简化问题,以了解它们为何不同。这两个函数之间的唯一区别是两个表达式:

(repeat (average-damping (lambda (y) (/ x (expt y (- n 1)))))
        num-repetitions)

((repeat average-damping num-repetition)
   (lambda (y) (/ x (expt y (- n 1)))))

为了简化我们的讨论,我们假设num-repetition等于2,并且有一个比那个lambda更简单的函数,例如以下函数:

(define (succ x) (+ x 1))

所以现在有两个不同的部分:

(repeat (average-damping succ) 2)

((repeat average-damping 2) succ)

现在,对于第一个表达式,(average-damping succ)返回一个数值函数,该函数计算参数与其后继参数之间的平均值:

(define h (average-damping succ))
(h 3) ; => (3 + succ(3))/2 = (3 + 4)/2 = 3.5

因此,表达式(repeat (average-damping succ) 2)等效于:

(lambda (x) ((compose h h) x)

等效于:

(lambda (x) (h (h x))

同样,这是一个数字函数,如果将此函数应用于3,则具有:

((lambda (x) (h (h x)) 3) ; => (h 3.5) => (3.5 + 4.5)/2 = 4

在第二种情况下,我们有(repeat average-damping 2)产生了完全不同的功能:

(lambda (x) ((compose average-damping average-damping) x)

等效于:

(lambda (x) (average-damping (average-damping x)))

您可以看到,这次的结果是一个高级函数,而不是整数函数,该函数接受函数x并应用两次average-damping函数对此。让我们通过将此函数应用于succ并将结果应用于数字3来验证这一点:

(define g ((lambda (x) (average-damping (average-damping x))) succ))
(g 3) ; => 3.25

结果的差异不是由于数值逼近,而是由于计算方法不同:首先(average-damping succ)返回函数h,该函数计算参数与其后继参数之间的平均值。然后(average-damping h)返回一个新函数,该函数计算参数与函数h的结果之间的平均值。这样的函数,如果传递了数字3,则首先计算3和4之间的平均值,即3.5,然后计算3(同样是参数)和3.5(先前的结果)之间的平均值,得出3.25。

答案 1 :(得分:1)

repeat的定义需要

  ((repeat f k) x)  =  (f (f (f (... (f x) ...)))) 
                    ;   1  2  3       k

总共k个嵌套调用,分别f个。让我们这样写

                    =  ((f^k) x)

并定义

  (define (foo n)  (lambda (y)  (/ x (expt y (- n 1)))))
  ;       ((foo n)  y)  =  (/ x (expt y (- n 1)))

那么我们就有

  (nth-root-you x n k)  =  (fixed-point  ((average-damping (foo n))^k)   1.0)

  (nth-root-web x n k)  =  (fixed-point  ((average-damping^k)  (foo n))  1.0)

因此,您的版本会在 {执行的每个迭代步骤中使用一次平均阻尼k函数执行 (foo n) 步骤{1}} ;网络将 k -times-average-damped fixed-point作为其 迭代步骤。请注意,无论使用多少次,一次平均阻尼功能仍然仅是平均阻尼一次,并使用几次 >时间可能只会加剧问题,而不能解决问题。

对于(foo n),两个结果迭代步骤函数当然是等效的。

在您的情况下,k == 1,依此类推

k == 2

(your-step y)  =  ((average-damping (foo n)) 
                     ((average-damping (foo n))  y))                 ; and,

(web-step  y)  =  ((average-damping (average-damping (foo n)))  y)

我们有

((average-damping f)  y)  =  (average  y  (f y))

区别很明显。从上一个公式可以清楚地看出,平均阻尼用于在某些(your-step y) = ((average-damping (foo n)) (average y ((foo n) y))) = (let ((z (average y ((foo n) y)))) (average z ((foo n) z))) (web-step y) = (average y ((average-damping (foo n)) y)) = (average y (average y ((foo n) y))) = (+ (* 0.5 y) (* 0.5 (average y ((foo n) y)))) = (+ (* 0.75 y) (* 0.25 ((foo n) y))) ;; and in general: ;; = (2^k-1)/2^k * y + 1/2^k * ((foo n) y) 上抑制(foo n)可能不稳定的跳跃,并且y越高,阻尼效果越强。 / p>