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

Why do these two equivalent expressions in java and lisp have different outcomes?

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 使用默认 reader 设置读取它们的方式):

> (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

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

> (= 0.0026016448 0.0026016447)
t

? (= 0.0026016448 0.0026016447)
t

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