我查看了Clojure implementation中关于Ratio类型的新clojure.core/abs
实现,代码中似乎存在假定,使用clojure.lang.Ratio类型的内部详细信息,即分母始终为正(例如,请参阅类型Ratio中对isNeg和isPos方法的定义)。
我开始寻找违反该假定的示例,发现以下所有情况,所有这些情况都可能是由具有Long/MIN_VALUE作为分母和具有Long或更小的整数类型的分子表达式产生的类型Ratio的值所特有的。
$ clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.11.0-alpha4"}}}'
Clojure 1.11.0-alpha4
user=> (/ 1 Long/MIN_VALUE)
-1/-9223372036854775808
user=> (< (/ 1 Long/MIN_VALUE) 0) ;; This gives correct numerical answer
true
user=> (< (* 1 (/ 1 Long/MIN_VALUE)) 0) ;; This does not
false
user=> (abs (/ 1 Long/MIN_VALUE)) ;; Gives incorrect numerical answer
1/-9223372036854775808
user=> (< (abs (/ 1 Long/MIN_VALUE)) 0) ;; correct numerical answer
false
user=> (< (* 1 (abs (/ 1 Long/MIN_VALUE))) 0) ;; incorrect numerical answer
true
我已经仔细检查了Clojure实现中Numbers.java源文件中Ratio的其他实例,据我所知,唯一的问题是LongOps类中命名的divide方法。如果此方法通过检查分子和/或分母等于Long/MIN_VALUE的特殊情况,并在该情况下行为有所不同来避免这个问题,我没有发现其他错误。
如果分子等于Long/MIN_VALUE,存在另一个问题,其根本原因与LongOps divide方法相同
user=> (/ Long/MIN_VALUE -3) ;; should return positive value, but returns negative value
-9223372036854775808/3
user=> (< (/ Long/MIN_VALUE -3) 0)
true