在Coursera课程Functional Programming Principles in Scala
中,讲师讨论了Fixed Point
,并写了一些简单的实现。
def isCloseEnough(x: Double, y: Double) =
math.abs((x - y) / x) / x < tolerance
def fixedPoint(f: Double => Double)(guess: Double) = {
def iterate(guess: Double): Double = {
val next = f(guess)
if (isCloseEnough(guess, next)) next
else iterate(next)
}
iterate(guess)
}
这样的实现将允许以下函数f(x) = 1 + x
具有固定点。
然而,这不应该永远不会发生。 如在此函数图中:
这就是维基百科所说的:
并非所有函数都有固定点:例如,如果f是函数 在实数上定义为f(x)= x + 1,那么它没有固定的 点,因为对于任何实数,x永远不等于x + 1。
这里的重点在于isCloseEnough
,我不知道为什么会这样写。
我在这里了解isCloseEnough
及其实施方式
这就是全部。
答案 0 :(得分:2)
该算法并不完美,显然取决于您对容差的选择。如果我们检查isCloseEnough
:
def isCloseEnough(x: Double, y: Double) =
math.abs((x - y) / x) / x < tolerance
它非常类似于:
| x - y | / x^2 < tolerance
除了由于某种原因它没有取x
的外部分区的绝对值,这在x
为负时完全打破了算法。
我们的想法是,我们通过找到任意关闭到x
的{{1}}找到一个固定点,即f(x)
和x
之间的差异f(x)
尽可能小(低于一些容差)。如果我们能够快速找到固定点,这种方法很好:
scala> fixedPoint(math.sqrt)(2)
res2: Double = 1.0000846162726942
此处,固定点为x = 1
,其中math.sqrt(1) = 1
。我用了tolerance = 0.0001
。如果我使用较小的东西,我显然会更接近固定点1
。
但现在说我有:
def f(x: Double): Double = x + 1
scala> fixedPoint(f)(1)
res4: Double = 102.0
找到大约102.0
的固定点。显然,这是错误的,但这是因为x
和f(x)
之间的差异总是 1
这个函数,并且x
得到更大,1 / x^2
越来越小,直到它低于tolerance
。如果我让tolerance
更小,我会找到一个更大的固定点。
val tolerance = 0.000000001
scala> fixedPoint(f)(1)
res5: Double = 31624.0
这显然也是错误的。但问题是,对于某些固定点,我应该能够使tolerance
任意小,并且仍能获得一致的结果。使用此功能,很明显,对于任何固定的tolerance
,最终1 / x^2
将小于它。 但是,对于任何x
,我总是可以选择足够小的tolerance
,以便1 / x^2
总是落在它之外,所以没有固定点。
这不是一个数学证明,但重点是该算法存在某些标准的缺陷。