Performance 如何使阶乘更快?

Performance 如何使阶乘更快?,performance,algorithm,clojure,Performance,Algorithm,Clojure,我用Clojure做了一个简单的阶乘程序 (defn fac [x y] (if (= x 1) y (recur (- x 1) (* y x))) ) (def fact [n] (fac n 1)) 怎样才能做得更快?如果可以用更快的方法来完成。您可以在这里找到许多快速阶乘算法: 如上所述,Clojure并不是最好的语言。考虑使用C、C++、FORTRAN、 请小心使用的数据结构,因为阶乘增长非常快。您可以在这里找到许多快速阶乘算法: 如上所述,Clojure并不是最好的语

我用Clojure做了一个简单的阶乘程序

(defn fac [x y] 
     (if (= x 1) y (recur (- x 1) (* y x)))
)

(def fact [n] (fac n 1))

怎样才能做得更快?如果可以用更快的方法来完成。

您可以在这里找到许多快速阶乘算法:

如上所述,Clojure并不是最好的语言。考虑使用C、C++、FORTRAN、


请小心使用的数据结构,因为阶乘增长非常快。

您可以在这里找到许多快速阶乘算法:

如上所述,Clojure并不是最好的语言。考虑使用C、C++、FORTRAN、


请小心使用的数据结构,因为阶乘增长非常快。

借助您自己的
fact
函数(或任何其他函数),我们可以定义这个极快的版本:

(def fact* (mapv fact (cons 1 (range 1 21))))
这将为常数时间范围为1到20的参数提供正确的结果。超出该范围,您的版本也不会给出正确的结果(即,
(事实21)
)存在整数溢出)

编辑:这里有一个改进的实现,它不需要另一个
事实
实现,不会溢出,并且在定义过程中应该更快,因为它不会从头开始计算其查找表中的每个条目:

(def fact (persistent! (reduce (fn [v n] (conj! v (*' (v n) (inc n))))
                               (transient [1])
                               (range 1000))))
编辑2:对于不同的快速解决方案,即在不建立查找表的情况下,最好使用已经高度优化的库。谷歌的通用工具库Guava包含一个阶乘实现


通过添加此Leiningen依赖项将其添加到项目中:
[com.google.guava/guava“15.0”]
。然后,您需要
(导入com.google.common.math.bigingermath)
,然后可以使用
(bigingermath/factorial n)
调用它。借助于您自己的
fact
函数(或任何其他函数),我们可以定义这个极快的版本:

(def fact* (mapv fact (cons 1 (range 1 21))))
这将为常数时间范围为1到20的参数提供正确的结果。超出该范围,您的版本也不会给出正确的结果(即,
(事实21)
)存在整数溢出)

编辑:这里有一个改进的实现,它不需要另一个
事实
实现,不会溢出,并且在定义过程中应该更快,因为它不会从头开始计算其查找表中的每个条目:

(def fact (persistent! (reduce (fn [v n] (conj! v (*' (v n) (inc n))))
                               (transient [1])
                               (range 1000))))
编辑2:对于不同的快速解决方案,即在不建立查找表的情况下,最好使用已经高度优化的库。谷歌的通用工具库Guava包含一个阶乘实现

通过添加此Leiningen依赖项将其添加到项目中:
[com.google.guava/guava“15.0”]
。然后您需要
(导入com.google.common.math.BigIntegerMath)
,然后可以使用
(BigIntegerMath/factorial n)
调用它

(defn fact [n] (reduce *' (range 1 (inc n))))
'告诉Clojure透明地使用BigInteger以避免溢出

以下是我最喜欢的:

(defn fact [n] (reduce *' (range 1 (inc n))))

'告诉Clojure透明地使用BigInteger以避免溢出

首先,如果你需要快速的东西,不要使用Clojure尝试将
x
y
注释为int。此外,您可能对Clojure中的简单性能优化感兴趣。一个实用的建议是不要使用阶乘。例如,如果您想要
n/(n-k),您可以在单个循环/递归中处理它,而无需计算
n
(n-k),这样做既快又可靠(不太可能溢出)。使用阶乘函数作为构建块很少是一个好主意,因为它增长如此之快(在溢出32位整数IIRC之前只有13个不同的阶乘)。好吧,对于初学者来说,如果需要快速的东西,不要使用Clojure。;-)尝试将
x
y
注释为int。此外,您可能对Clojure中的简单性能优化感兴趣。一个实用的建议是不要使用阶乘。例如,如果您想要
n/(n-k),您可以在单个循环/递归中处理它,而无需计算
n
(n-k),这样做既快又可靠(不太可能溢出)。使用阶乘函数作为构建块很少是一个好主意,因为它增长如此之快(在溢出32位整数IIRC之前只有13个不同的阶乘)。哪里记录了*?这里:哪里记录了*?这里: