作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图找出为什么此 Clojure 代码与其 Java 等效代码之间存在性能差异。 Clojure 代码:
(ns trigperf.core (:gen-class))
(deftype city [^String name ^double latr ^double lonr
^double sinlat ^double coslat ^double sinlon ^double coslon])
(defn dist [^city city1 ^city city2]
(let [st1 (double (.sinlat city1)) st2 (double (.sinlat city2))
ct1 (double (.coslat city1)) ct2 (double (.coslat city2))
ln1 (double (.lonr city1)) ln2 (double (.lonr city2))]
(Math/acos (+ (* st1 st2) (* ct1 ct2 (Math/cos (Math/abs (- ln1 ln2))))))))
(defn cost [route]
(reduce + (map dist route (drop 1 route))))
(defn test-data []
(take 100 (repeatedly
#(let [latr (/ (* (- (rand 180) 90) Math/PI) 180)
lonr (/ (* (- (rand 360) 180) Math/PI) 180)]
(city. "" latr lonr
(Math/sin latr) (Math/cos latr)
(Math/sin lonr) (Math/cos lonr))))))
(defn run-test []
(let [data (test-data)] (time (dotimes [i 99999] (cost data)))))
(defn -main [& args] (run-test))
Java 等价物:
public class City {
public String name;
public double latr;
public double lonr;
public double sinlat;
public double coslat;
public double sinlon;
public double coslon;
public City(String n, double a, double b, double c, double d, double e, double f) {
name = n; latr = a; lonr = b;
sinlat = c; coslat = d; sinlon = e; coslon = f;
}
}
public class Trigperf {
public static City[] test_data() {
City[] arr = new City[100];
for (int c=0; c < 100; ++c) {
double latr = (((Math.random() * 180) - 90) * Math.PI) / 180;
double lonr = (((Math.random() * 180) - 90) * Math.PI) / 180;
arr[c] = new City("", latr, lonr, Math.sin(latr), Math.cos(latr),
Math.sin(lonr), Math.cos(lonr));
}
return arr;
}
public static double dist(City city1, City city2) {
return Math.acos((city1.sinlat * city2.sinlat) +
(city1.coslat * city2.coslat *
(Math.cos (Math.abs (city1.lonr - city2.lonr)))));
}
public static double cost(City[] route) {
double acc = 0;
for (int c=0; c < route.length - 1; ++c) {
acc += dist(route[c], route[c + 1]);
}
return acc;
}
public static void run_test() {
City[] data = test_data();
long start = System.currentTimeMillis();
for (int c=0; c < 99999; ++c) { cost(data); }
long stop = System.currentTimeMillis();
System.out.format( "Elapsed: %dms\n", stop - start);
}
public static void main(String[] args) {
run_test();
}
}
运行 Clojure 代码大约需要 4 秒,运行 Java 版本需要 2 秒。所以 Clojure 需要两倍的时间。但我已经在我能想到的所有地方进行了类型提示,并确保没有反射警告。如何提高 Clojure 代码的速度以接近 Java 代码的速度?
最佳答案
clojure 代码使用的数学略有不同,因为每个操作都在检查溢出,如果溢出将抛出异常:
user> (* Long/MAX_VALUE 2)
ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1501)
user> (unchecked-add Long/MAX_VALUE 2)
-9223372036854775807
因此,您可以通过关闭安全装置来多挤一点。并且根据历史记录,旧的(现在是古老的)版本的 clojure 也会默认升级到更大的类型,后来决定不值得花时间。还要注意 /
函数的使用,因为它会在可能的时候计算比率,这涉及计算 GCD,因此它可以在其中隐藏一些成本:
user> (/ (int 2) (int 6))
1/3
user> (quot (int 2) (int 6))
0
user> (/ (float 2) (float 6))
0.3333333333333333
虽然这看起来不像这里的情况,因为您要乘以 PI,这将使它成为 double 值。
关于java - Clojure 数值表现 : What am I missing in my code?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33027872/
我是一名优秀的程序员,十分优秀!