Clojure 在函数中减少溢出,但在直接传递给 REPL 时不会溢出

Posted

技术标签:

【中文标题】Clojure 在函数中减少溢出,但在直接传递给 REPL 时不会溢出【英文标题】:Clojure reduce overflows when in function, but not when passed directly into REPL 【发布时间】:2017-05-02 04:38:31 【问题描述】:

我在调试显然只在我在函数中使用语句时才会发生的溢出时遇到了很大的麻烦。

这是我的功能:

(defn sum-records
    [senset votemap]
    (let [voteset (select-keys votemap senset)]
        (reduce (fn [v1 v2] (mapv + v1 v1)) (vals voteset))))

问题似乎来自reduce。但是,当我在数据的 repl 中单独运行该行时,它工作得非常好。我已经检查以确保我在 repl 测试的数据确实与函数中的 voteset 相同。我什至在函数中插入了println 语句来验证这一点。

我真的被困在这里,非常感谢任何帮助!

【问题讨论】:

【参考方案1】:

你可能有整数溢出:

 (reduce (fn [v1 v2] (mapv + v1 v1)) (repeat 1000 (range 10)))
 => ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1501)

您必须确保输入数据是其他数据,或者在 + 函数中强制转换为 bigint,或者使用 @ClojureMostly 指出的支持任意精度的 +'。

所有这些方法都有效:

  (reduce (fn [v1 v2] (mapv +' v1 v1)) (repeat 1000 (range 0 10)))
   => [0N 535754303593133660474212524...

  (reduce (fn [v1 v2] (mapv + v1 v1)) (repeat 1000 (range 0N 10N)))
   => [0N 535754303593133660474212524...

  (reduce (fn [v1 v2] (mapv + v1 v1)) (repeat 1000 (map bigint (range 10))))
   => [0N 5357543035931336604742125245300009052...

  (reduce (fn [v1 v2] (mapv #(+ (bigint %1) (bigint %2)) v1 v1)) (repeat 1000 (range 10)))
   => [0N 53575430359313366...

【讨论】:

为什么不使用+' 不知道,我会更新答案,谢谢 哦,不,我意识到我的错误就在眼前!我想用我的 reduce 做的是将 v1v2 添加在一起!当我单独测试我的线时,我从来没有溢出过,因为我的数据量不是太大,所以我不明白为什么它会导致函数溢出!非常感谢您的帮助!当我在您的 mapv 行中看到重复的 v1 时,它提示我重新检查我的来源!

以上是关于Clojure 在函数中减少溢出,但在直接传递给 REPL 时不会溢出的主要内容,如果未能解决你的问题,请参考以下文章

clojure 减少不终止减少功能

包含混合向量和双精度的向量的 Clojure 减少函数

Clojure 的加载字符串在 repl 中有效,但在 `lein run` 中无效

如何转发可选参数

将空列表传递给函数以收集结果

如何使用 clojure.test 将值从夹具传递到测试?