在 Clojure 中使用浮点值的理念是什么?

What's the philosophy concerning the use of floating point values in Clojure?

目前我正在使用 Clojure-on-top-of-the-JVM。

计算期间的 Java language, which exposes the floating point functionality of the JVM, says that we get (exactly) IEEE-754 32-bit single-precision (Java "float") and 64-bit double precision (Java "double") representations and that the JVM may use an "extended precision" 实现("extended double" 的 80 位,在某些编程语言中也称为 "long double")。目前没有关于半精度或四倍精度的消息。

对于 Clojure-on-top-of-ECMAScript(即 ClojureScript),有一个底层 number type,恰好是 IEEE-754 64-位双精度浮点数。

似乎在 Clojure-on-the-JVM 的情况下,在所有需要浮点数的情况下都鼓励使用 "double"。甚至没有一种方法可以测试给定的事物是否是单精度浮点数,因为 float?(可能令人惊讶)测试事物是否是任何类型的浮点值。不一致的是,有一个 "cast to float" 的函数,叫做 float.

(defn whatf [x] [(double? x) (float? x) (type x)])

; a literal containing a decimal point is mapped to a 
; "Java double" (boxed)

(whatf 0.1)
;=> [true true java.lang.Double]

; an integer is a "Java long" (boxed), as expected:

(whatf 1)
;=> [false false java.lang.Long]

; you can cast to "float", which corresponds to "Java float".
; and "double?" returns false for that:

(whatf (float 1))
;=> [false true java.lang.Float]

; you can cast to "double":

(whatf (double 1))
;=> [true true java.lang.Double]

; operations on "double" yield "double" as expected:

(whatf (*(double 1) (double 1)))
;=> [true true java.lang.Double]

; operations on "float" force to "double" immediately:

(whatf (*(float 1) (float 1)))
;=> [true true java.lang.Double]

; of course one can always cast, but what's the use of that:

(whatf (float (*(float 1) (float 1))))
[false true java.lang.Float]

因此,鼓励程序员不要考虑精度,让 Clojure 为 him/her 选择——Clojure 自始至终选择 IEEE binary64。这是问题的要点吗?

我会说 Clojure/Java 使得仅使用 64 位 Java double 类型变得简单,原因如下:

  1. double 是您在编写浮点文字数字时获得的默认类型,例如1.0
  2. double 是默认类型 return 在进行运算时 return 是一个浮点类型
  3. 对于要使用 Java 原始值的循环构造和函数参数以及 return 值,Clojure 支持双精度但不支持浮点。

可以使用 float 数组和单独的装箱 Float 值,但您必须多做一些工作。