【问题标题】:Quickest way to calculate the Euclidean-Distance between two points in N-Dimensional space计算 N 维空间中两点之间欧几里得距离的最快方法
【发布时间】:2012-08-24 03:50:03
【问题描述】:

我必须计算 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。

【问题讨论】:

    标签: objective-c euclidean-distance


    【解决方案1】:

    绝对摆脱pow()。对此的大部分优化取决于您如何使用它。您是否对非常大的 N 执行一次此操作并且花费的时间太长?或者,更有可能的是,您是否在一个紧密的循环中多次执行此操作?

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

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

    您可以进行循环展开(即,将 N 分成例如 4 的块,并在 for 循环主体内显式写出 4 个连续值的计算。这具有欺骗编译器使用更多寄存器的效果用于即时计算——寄存器是您必须使用的最快的内存形式。此外,您可以利用预取(通过一次内存访问调用读取一段数据)。

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

    还有 50 万件其他事情可以尝试,但我想我会在这里停下来。祝你好运!

    【讨论】:

    • 除了矢量化之外,如果适合您的用例,您还可以尝试在多个内核上执行计算。
    • 不幸的是,BLAS 中提供的欧几里得范数函数实际上并没有达到我想要的效果。欧几里得范数,或者欧几里得长度,相当于计算N维空间中的一点到原点的距离,而不是两个不同的点。
    • @user1357607 是的,你必须先用*axpy 减去两个向量。代码类似于*axpy(N, -1, p, 1, q, 1); answer = *nrm2(N, p, 1);
    • 谢谢。冒着烦人的风险,是否还有一个函数可以将两个向量逐个元素相乘?
    • MKL 现在是免费的,而且速度非常快。
    【解决方案2】:

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

    你需要做一个温度,然后把它平方。

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-12
      • 1970-01-01
      • 2020-09-25
      • 2014-06-14
      • 1970-01-01
      • 2020-03-05
      • 2011-01-29
      • 1970-01-01
      相关资源
      最近更新 更多