为什么java和lisp中这两个等价的表达式有不同的结果?

问题描述

lisp 中的表达式为:

(* (+ a b) (- a (/ 1 b)))

Java 中的等价表达式(我认为)是:

(a + b) * (a - (1/b));

但是当我向两者中输入相同的 ab float 值时,它们的计算结果不同。这是为什么?

解决方法

如果您使用相同的浮点类型(两者都是单打或双打),那么您所看到的可能是打印浮点数的行为的不同。很有可能这些数字实际上是一样的。默认的 CL 打印机(或应该)非常小心地打印足够的信息,以便浮点数可以读回并与它打印的相同。所以给定

(defun f (a b)
  (* (+ a b) (- a (/ 1 b))))

然后我们可以用

测试读写一致性
(defun tsrp (x)
  (with-standard-io-syntax
    (eql (read-from-string (write-to-string x))
         x)))

现在在一个实现中(第一个例子是使用单精度第二个双精度,这是 CL 应该如何使用默认读取器设置读取这些):

> (f 1.001 1.0003)
0.0026016448

> (tsrp (f 1.001 1.0003))
t

> (f 1.001d0 1.0003d0)
0.002601509937018715D0

> (tsrp (f 1.001d0 1.0003d0))
t

在另一个:

? (f 1.001 1.0003)
0.0026016447
? (tsrp (f 1.001 1.0003))
t
? (f 1.001d0 1.0003d0)
0.002601509937018715D0
? (tsrp (f 1.001d0 1.0003d0))
t

请注意,两种实现在单精度情况下打印出不同的外观结果。但是你可以确认这两种表示是同一个单浮点数:

> (= 0.0026016448 0.0026016447)
t

? (= 0.0026016448 0.0026016447)
t

我不知道如何让 Java 打印一个浮点数,以便它可以像这样读回:我认为它可能是 %s 格式控件。如果这是对的,并且您确保您的浮点类型相同,那么您应该获得相同的表示,或者仅在数字上有所不同的表示实际上并不重要(您可以检查,使用与上述等效的代码).