2024 Clojure状态调查!中分享你的想法。

欢迎!请见关于页面,了解更多有关如何使用该平台的信息。

0
Clojure
已关闭

我在检查Clojure实现中类型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时检测特殊案件,并在此情况下表现不同,我看不出有其他bug。

如果分子等于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
已关闭,并注明:已在Clojure 1.12.0-alpha4中修复

2 个答案

0
by
选中 by
 
最佳回答

将此问题报告为 https://clojure.atlassian.net/browse/CLJ-2694 并添加了一个补丁来检测对 Long/MIN_VALUE 的使用,并委托给 bigint 实现。将这些情况添加为测试。

0
by

我认为这已被 https://clojure.atlassian.net/browse/CLJ-1254 覆盖。

by
我不太清楚,但我想修复一个不一定能修复另一个,即每个问题后面的 Java 方法是不相交的,至少今天是这样。
by
你能澄清一下吗?
嗯,你可能是对的,而且/在一些情况下似乎确实返回了通过Ratio的确切答案,但上述测试用例显示,在某些情况下它甚至返回了错误答案,即使它返回了Ratio。这些情况并不是返回值被存储在Long/long中的情况。

这种情况似乎有些奇怪,几乎在所有情况下,/都返回了一个精确的答案,但是上面的测试用例显示,在某些情况下它并不返回正确的答案,即使在返回Ratio的情况下也是如此。这不是那种返回值存储在Long/long中的情况。
这个问题的测试用例给出了错误的答案,是因为LongOps方法中的divide实现方式。我相信CLJ-1254的根本原因是因为LongOps方法中的quotient实现方式,这可能是不同实现部分的独立错误。
...