请分享您的想法,参与 2024 Clojure 状态调查!)

欢迎!请参阅 关于 页面获取更多关于这如何工作的信息。

+1 投票
Clojure

这个问题与 问题 1555 有关,但涉及的类型不同,因此潜在的问题可能也不同。

在 bigint 与 float 之间,`rem` 返回的结果看起来非常不正确。注意使用 10000 作为除数与使用 1e4 的极大差异

user> (rem 9037601485536036300227801N 10000)
7801N
user> (long (rem 9037601485536036300227801N 1e4))
1073741824

test.check 提供了更清晰的、明显不正确的结果示例

user> (rem 9007199254740993N 2)
1N
user> (rem 9007199254740993N 2.0)
0.0

下面是一个生成测试用例以重现这个结果

(clojure.test.check/quick-check
 100 (prop/for-all [l gen/size-bounded-bigint
                    r (gen/fmap inc gen/nat)]
                   (== (rem l (double r))
                       (rem l (long r)))))

1 答案

0 投票
 
最佳答案

我相信当前的 Clojure/JVM 实现 (rem 9007199254740993N 2.0)(rem (double 9007199254740993N) 2.0) 相同,因此对于足够大的 BigInt 值会在最低有效位进行某种舍入,所以对于小的除数会肯定给出错误的数值答案。

处理任意精度级别的任意类型数值参数对,对于所有受支持的类型来说,在思维、开发、测试、修复意外情况等方面似乎是一个艰巨的任务。

这里我不是决策者,但如果Clojure核心开发团队将这种行为归入“如果你想要精确答案,那就不要使用浮点数/双精度浮点数,可以去阅读‘每个计算机科学家都应该知道关于浮点运算的知识’””,我也不会感到惊讶。

https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

by
这是一个合理的回应,也可能是对核心团队回应的正确猜测!生成测试只是将这个问题摆在你面前 :) 这本身就是一个教训,也是为什么要使用test.check的另一个原因。
...