我正在计算Clojure中3d点云的边界框。点云表示为Java原始浮点数组,点云中的每个点都使用4个浮点数存储,其中最后一个浮点数未使用。像这样:
[x0 y0 z0 u0 x1 y1 z1 u1 .... ]
点云的大小是19200,即阵列中的4 * 19200浮点数。
这些值中的一些可能不是有限的(它们是无限的或NaN)。因此,任何包含非有限值的点都应完全从计算中排除。我已经在Java和Clojure中实现了这个计算,但由于某种原因,Clojure版本仍然慢了4到5倍。
这就是Clojure代码的样子:
(defn good-compute-bbox [^floats data]
(let [n (alength data)]
(loop [i (int 0)
minx (float (aget data 0))
maxx (float (aget data 0))
miny (float (aget data 1))
maxy (float (aget data 1))
minz (float (aget data 2))
maxz (float (aget data 2))]
(if (< i n)
(let [x (float (aget data (unchecked-add i 0)))
y (float (aget data (unchecked-add i 1)))
z (float (aget data (unchecked-add i 2)))]
(if (and (Float/isFinite x)
(Float/isFinite y)
(Float/isFinite z))
(recur (unchecked-add-int i (int 4))
(min minx x)
(max maxx x)
(min miny y)
(max maxy y)
(min minz z)
(max maxz z))
(recur (unchecked-add-int i (int 4))
minx
maxx
miny
maxy
minz
maxz
))
)
[minx maxx miny maxy minz maxz]))))
这就是Java代码的样子:
public class BBox {
public static float[] computeBBox(float[] data) {
long n = data.length;
float[] result = new float[6];
float minx = data[0];
float maxx = data[0];
float miny = data[1];
float maxy = data[1];
float minz = data[2];
float maxz = data[2];
for (int i = 0; i < n; i += 4) {
float x = data[i + 0];
float y = data[i + 1];
float z = data[i + 2];
if (java.lang.Float.isFinite(x) &&
java.lang.Float.isFinite(y) &&
java.lang.Float.isFinite(z)) {
minx = x < minx? x : minx;
maxx = x > maxx? x : maxx;
miny = y < miny? y : miny;
maxy = y > maxy? y : maxy;
minz = z < minz? z : minz;
maxz = z > maxz? z : maxz;
}
}
result[0] = minx;
result[1] = maxx;
result[2] = miny;
result[3] = maxy;
result[4] = minz;
result[5] = maxz;
return result;
}
};
我的问题是:我可以对Clojure代码进行哪些更改,使其运行速度与Java代码一样快?如果您测试了代码并测量了加速度,则可以获得奖励。
如果您想重现实验并published on my Github repository here。
答案 0 :(得分:3)
这里的罪魁祸首 - 我从你的代码中可以看出你已经怀疑 - 是min
。它适用于各种类型,并不是那么快。
使用Apache的公共快速数学,你可以获得Java的10%以内:
(defn primitive-compute-bbox-new [^floats data]
(let [n (alength data)]
(loop [i (int 0)
minx (aget data 0)
maxx (aget data 0)
miny (aget data 1)
maxy (aget data 1)
minz (aget data 2)
maxz (aget data 2)]
(if (< i n)
(let [x (aget data (unchecked-add i 0))
y (aget data (unchecked-add i 1))
z (aget data (unchecked-add i 2))]
(if (and (Float/isFinite x)
(Float/isFinite y)
(Float/isFinite z))
(recur (unchecked-add-int i 4)
(FastMath/min (float minx) x)
(FastMath/max (float maxx) x)
(FastMath/min (float miny) y)
(FastMath/max (float maxy) y)
(FastMath/min (float minz) z)
(FastMath/max (float maxz) z))
(recur (unchecked-add-int i 4)
minx
maxx
miny
maxy
minz
maxz)))
[minx maxx miny maxy minz maxz]))))
部:
[org.apache.commons/commons-math3 "3.6.1"]