繁体   English   中英

计算N维空间中两点之间欧氏距离的最快方法

[英]Quickest way to calculate the Euclidean-Distance between two points in N-Dimensional space

我必须计算N维空间中两点之间的欧氏距离,速度至关重要。 我有两个C风格浮点数组,表示N维空间中的两个点。

它们之间距离的公式是(^仅意味着幂,而不是XOR):sqrt(sum((p1-q1)^ 2 +(p2-q1)^ 2 + ....(pn-qn) ^ 2))

我当前的代码如下所示:

sum = 0;
for(int i=0;i<N;++i){
    sum += pow(p[i]-q[i],2);
sqrt(sum)

这段代码很慢,我想知道是否有任何库来加快速度? 我想有人写了一个关于在c上对数组执行数学运算的快速库,它允许我快速对数组进行元素运算。

编辑:在回答nevsan时,我正在做一些小N的计算,大约10或20。

绝对摆脱pow() 优化的很大一部分取决于您如何使用它。 对于非常大的N,你这样做了吗?它需要太长时间? 或者,更有可能的是,你是在一个紧凑的循环中多次这样做的吗?

如果您使用的是非常大的N(> 1000左右),那么可以使用高度优化的数值库。 例如,BLAS具有*nrm2函数,该函数将计算欧几里德范数( dnrm2snrm2cnrm2znrm2 ,具体取决于数据类型[单,双,复单,复双])。 对于某些处理器架构, GotoBLAS可能是最快的。 MKL采用英特尔手动调整的BLAS实现,但它不是免费的。 最后, ATLAS是一个实现BLAS的自我调整库。

如果你有一个小的或不太大的N的紧密循环,那么你可能需要进行一些手动调整以使其更快。 您可以使用-O3-ftree-vectorize编译器标志打开自动矢量-ftree-vectorize 您也可以手动矢量化,但学习如何做到这一点可能会很痛苦。

你可以进行循环展开(也就是说,将N分成4个块,并明确地写出for循环体内4个连续值的计算。这会导致编译器使用更多寄存器进行即时计算---和寄存器是您必须使用的最快的内存形式。此外,您可以利用预取(通过一次内存访问调用读取一段数据)。

在这种情况下要做的另一件事是尝试覆盖您的一个输入。 也就是说,也许你可以将输出写入pq 这有帮助,因为当您准备写入时,您计算的p的位置仍将在缓存中。 缓存通常不会将数据写入内存,除非他们绝对必须 - 一个原因是需要缓存行,我们需要将最后一行放出。 通过写入其中一个输入,可以使用更少的缓存行。

还有50万个其他的东西要尝试,但我想我会在这里停下来。 祝好运!

我永远不会使用pow() - 我的猜测没有分析是这会减慢你的速度。

你需要制作一个温度,然后平方。

double diff = p[i] - q[i];
sum += diff*diff;

sqrt有点慢,但这里唯一的选择是一些近似值。 如果你有N>大约10,那么sqrt不会成为瓶颈。

还有像boost这样的库可能会加速这个,但首先尝试摆脱pow()。 请记住,diff * diff是一个浮点指令,其中pow()是为非整数幂等设计的整个程序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM