此方案代码如何返回值?



这段代码取自Sussman和Wisdom的《经典力学的结构和解释》,其目的是推导出(接近(主机支持的最小正浮点数。 https://github.com/hnarayanan/sicm/blob/e37f011db68f8efc51ae309cd61bf497b90970da/scmutils/src/kernel/numeric.scm

在我的机器上,在DrRacket中运行它会导致2.220446049250313e-016。

我的问题,是什么原因导致它甚至返回一个值?此代码是尾递归的,在某些时候计算机不能再除以 2 是有意义的。为什么不扔?

(define *machine-epsilon*
(let loop ((e 1.0))
(if (= 1.0 (+ e 1.0))
(* 2 e)
(loop (/ e 2)))))
*machine-epsilon*

这段代码是尾递归的,在某些时候计算机不能再除以 2 是有意义的。为什么不扔?

不,想法是不同的:在某些时候,计算机仍然可以除以2,但结果 (e( 变得与 0 无法区分 [upd:仅在浮点加法的上下文中 - 注释中提到的非常好的观点](e + 1.0 = 1.0,这正是if子句正在检查的内容(。我们确信"从机器的角度来看",之前的e仍然大于零(否则我们不会到达当前的执行点(,所以我们只需返回e*2

这种形式的let-binding是递归的语法糖。

在掌握语言并尽可能多地使用内核语言编写之前,您可以避免使用过多的语法,以专注于基本问题。 例如,在完整的 SICP 文本中,从不指定此语法糖进行迭代。

迭代的 r6rs 定义在这里。

此代码的目的不是查找机器可以支持的最小浮点数:而是查找最小的浮点数,epsilon使得(= (+ 1.0 epsilon) 1.0)为假。 这个数字很有用,因为它是你从数字相加得到的误差的上限,特别是你知道的是,比如说,(+ x y)在[(x+y(*(1 - epsilon(,(x+y(*(1 + epsilon(]范围内,其中在第二个表达式中+&c表示对数字的理想运算。

特别是(/ *machine-epsilon* 2)是一个完美的数字,例如(/ *machine-epsilon* 10000)也是如此,对于许多合理的x值,(* (/ *machine-epsilon* x) x)将非常接近*machine-epsilon*。 只是(= (+ (/ *machine-epsilon* 2) 1.0) 1.0)是真的。

我对浮点标准不够熟悉,但你可能想到的数字是Common Lisp所说的least-positive-double-float(或其变体(。 在球拍中,你可以通过以下公式推导出一些近似

值。
(define *least-positive-mumble-float*
;; I don't know what float types Racket has if it even has more than one.
(let loop ([t 1.0])
(if (= (/ t 2) 0.0)
t
(loop (/ t 2)))))

我不确定这是否允许提出一个例外:它在实践中没有,它得到了一个看起来合理的答案。

当你摆脱令人困惑的命名 let 符号时,它会变得更加清晰。

(define (calculate-epsilon (epsilon 1.0))
(if (= 1.0 (+ 1.0 epsilon))
(* epsilon 2)
(calculate-epsilon (/ epsilon 2))))
(define *machine-epsilon* (calculate-epsilon))

是代码实际的作用。 所以现在我们看看命名的 let 表达式有什么好处。 它在本地定义函数并运行它。只是函数的名称loop非常不精确且令人困惑,将 epsilon 命名为e是一个非常不愉快的选择。命名对于可读代码来说是最重要的。

因此,SICP 的这个示例应该是错误命名选择的示例。(好吧,也许他们这样做是故意训练学生的(。

命名的 let 定义并调用/运行函数/过程。避免它会导致更好的代码 - 因为更清晰。

在普通的lisp中,这样的结构会表达得更清楚:

(defparameter *machine-epsilon*
(labels ((calculate-epsilon (&optional (epsilon 1.0))
(if (= 1.0 (+ 1.0 epsilon))
(* epsilon 2)
(calculate-epsilon (/ epsilon 2)))))
(calculate-epsilon)))

在 CLISP 实现中,这提供了:1.1920929E-7

最新更新