我正在学习clojure并经历了clojure-koan练习.其中一个练习是关于实现阶乘功能.我在玩的时候注意到:
我的递归实现似乎适用于大数:
(defn factorial-1 [n]
(loop [n n f 1]
(if (= n 1)
f
(recur (dec n) (* f n)))))
Run Code Online (Sandbox Code Playgroud)
(factorial-1 1000N)在REPL中调用会产生一个数字:402387260077093773...
但是,当我尝试以下懒惰序列方法时:
(defn factorial-2 [n]
(reduce * 1 (range 1 (inc n))))
Run Code Online (Sandbox Code Playgroud)
调用(factorial-2 1000N)REPL会产生错误:
ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1388)
Run Code Online (Sandbox Code Playgroud)
为什么看似懒惰的序列方法会导致整数溢出错误?
尽管传递了1000N,但您实际上从未在乘法中使用任何bigint,因为您只使用该数字来确定计算的结束.你开始乘法1,然后乘以1,然后2,依此类推.如果修改factorial-2了使用bigint的定义,则会得到预期的行为:
(defn factorial-2 [n]
(reduce * 1N (range 1 (inc n))))
Run Code Online (Sandbox Code Playgroud)
或者你可以简单地使用*'函数。
(defn factorial-3 [n]
(reduce *' (range 1 (inc n))))
Run Code Online (Sandbox Code Playgroud)
*'函数支持任意精度。Long如果数字在 范围内,则返回Long。如果范围超出 Long 范围,则会返回BigInt。