我正在研究[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-point
,average-damp
和repeated
过程 1.43 。假设您需要的任何算术运算是 可作为基元使用。
我的答案(注意顺序为repeat
和average-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))))
答案 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>