8

在我的clojure研究期间,我发现了这一点:

;Clojure 1.4.0
(def neg_inf -1E-400)
(cond
    (= neg_inf 0) "Zero"
    (< neg_inf 0) "Negative"
    (> neg_inf 0) "Positive"
    :default "Neither"
)
;#'user/neg_inf
;user=> "Neither"

它是一个错误吗?

然后,我尝试了:

(Math/signum -1E-400) ;-0.0

这是我发现的一种方法,可以发现某个数字何时被视为 -0.0 :

(Math/copySign 1. -0.) ;-1.0
(Math/copySign 1. -1E-99999999999999999999999);-1.0

这样,我可以知道一个数字是否为负,即使它非常接近于零。

所有这一切都是因为我试图解决这个问题:

(defn hexadecimal-to-degrees [rah ram ras]
     { :pre [ (>= rah 0) (< rah 24) (>= ram 0) (< ram 60) (>= ras 0) (< ras 60) ]
       :post [ (>= % 0) ]
     }
     (/ (+ rah (/ ram 60) (/ ras 3600)) 15)
)

(hexadecimal-to-degrees -1E-400 -1E-400 -1E-400)
;-0.0 ; OMG, no Assert failed here!

由于赤经(地球经度的天体等价物)没有负值,我正在测试后置条件是否以保证无论我传递什么数字都不会为 RA 返回负值的方式传递给功能..

4

2 回答 2

8

我怀疑在(= 0 -1E-400)后台使用java的Double.equals()方法,它将正零和负零视为不相等。此行为违反了 IEEE 浮点标准。其他比较运算符转换为符合标准的其他方法,即将+0.0 和-0.0 视为相等。

要获得符合标准的行为,请使用数字等价运算符==。因此,(== 0 -0.0)评估为true

更多关于维基百科上的有符号和无符号零:http ://en.wikipedia.org/wiki/Signed_zero

更笼统地说:比较浮点数是否相等应该总是引起怀疑。

于 2012-09-18T12:06:05.920 回答
2

请记住,Doubles 的行为意味着处理器时间和准确性之间的性能折衷。Clojure 使使用 BigDecimal 变得很容易,BigDecimal 的计算成本更高,但具有更好的准确性保证。您可以通过在文字数字后附加“M”来指定 BigDecimal 数字文字,并且所有数字运算符都接受 BigDecimal。与您的示例相关的快速试驾:

user> (type -1E-400)
java.lang.Double
user> (type -1E-400M)
java.lang.BigDecimal

user> (= 0M -1E-400M)
false
user> (<= 0M -1E-400M)
false
user> (< 0M -1E-400M)
false
user> (>= 0M -1E-400M)
true
于 2012-09-18T15:42:02.510 回答