Sco*_*ach 2 java performance clojure
加快此功能的最佳简单方法是什么?根据Criterium,Java中的等效代码快了近50倍。
我敢打赌,如果我使用Java Array并减少装箱数量,这将大有帮助,但我想我会先在这里发布,看看是否有我犯的任何基本错误,可以很容易地解决。注意,我已经为Clojure指出了(double ...),它极大地提高了性能,但仍然没有Java那样。我还首先使用(double-array ...)而不是在函数内部使用(vec ...)转换了seq,这也提高了性能,但是再次,与Java没什么不同。
(defn cosine-similarity [ma mb]
(let [va (vec ma), vb (vec mb)]
(loop [p (double 0)
na (double 0)
nb (double 0)
i (dec (count va))]
(if (neg? i)
(/ p (* (Math/sqrt na) (Math/sqrt nb)))
(let [a (double (va i))
b (double (vb i))]
(recur (+ p (* a b))
(+ na (* a a))
(+ nb (* b b))
(dec i)))))))
Run Code Online (Sandbox Code Playgroud)
请注意,ma和mb都是序列,每个序列包含200个Double。在Java版本中,它们作为double [] args传递。
使用(double 0)没有性能上的好处,0.0直接指定(双字面量)不会带来任何好处。
如果您传入ma和mbas double-array并将args暗示为doubles,不要将它们转换为vector vec,而是使用aget进行元素查找,则会获得明显更好的性能。这应该使您获得非常接近Java代码性能的东西。
该double如果使用双数组作为函数参数的让利块内部通话将不再需要。
最终结果应如下所示:
(defn cosine-similarity [^doubles ma ^doubles mb]
(loop [p 0.0
na 0.0
nb 0.0
i (dec (count va))]
(if (neg? i)
(/ p (* (Math/sqrt na) (Math/sqrt nb)))
(let [a (aget va i)
b (aget vb i)]
(recur (+ p (* a b))
(+ na (* a a))
(+ nb (* b b))
(dec i))))))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
350 次 |
| 最近记录: |