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

欢迎!请参阅关于页面以了解更多关于此如何工作。

0
Clojure
已关闭

我在查看新的 clojure.core/abs 实现,在类型 Ratio 上,发现代码中有一个假设,即类型 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 实现 source 文件 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
已关闭,附言:已修复在 Clojure 1.12.0-alpha4 中

2 个答案

0

已选择
 
最佳答案

将此作为https://clojure.atlassian.net/browse/CLJ-2694提交,并添加了一个补丁以检测Long/MIN_VALUE的使用并转用到bigint实现。添加了这些用例作为测试。

0

我认为这已经由https://clojure.atlassian.net/browse/CLJ-1254涵盖。

我脑海中没有这方面的知识,但我认为修复一个问题并不一定能修复另一个问题,即每个问题背后的Java方法至少在今天是相互独立的。
能否澄清一下?
嗯,你可能是对的,或者其中一些内容可能属于这个WontFix JIRA问题:[https://clojure.atlassian.net/browse/CLJ-1253](https://clojure.atlassian.net/browse/CLJ-1253)

看来,或者说在几乎所有情况下,使用 `/` 返回一个完整的答案(通过Ratio),这似乎有些奇怪,但上面的测试用例表明,在某些情况下,即使返回了Ratio,它也不会返回正确的答案。这些情况并不涉及将返回值存储为Long/long。
这个问题的测试用例给出了错误的答案是因为LongOps方法的除法实现。我认为CLJ-1254的根源是因为LongOps方法的比例实现,这些可能是独立的、在不同的实现部分的缺陷。
...