Clojure中的负数小数

时间:2012-09-18 11:26:42

标签: 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返回负值,无论如何 数字我传递给函数..

2 个答案:

答案 0 :(得分:8)

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

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

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

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

答案 1 :(得分:2)

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

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
相关问题