【问题标题】:Given r^2, is there an efficient way to compute r^3?给定 r^2,有没有一种有效的方法来计算 r^3?
【发布时间】:2011-12-09 13:19:03
【问题描述】:
double r2 = dx * dx + dy * dy;
double r3 = r2 * sqrt(r2);

第二行可以换成更快的吗?不涉及sqrt的东西?

【问题讨论】:

  • @nyarlathotep:假设rsqrt(dx * dx + dy * dy)
  • @nyarlathotep 你错过了重点。如果 r = (dxdx + dydy)^(1/2),则 r2 = r^2。但这不是问题。
  • 我要冒昧地说,顺便提一下问题,从技术上讲,答案是否定的。原因很简单,如果给你 r^2,你不知道 r 的符号,那么如何计算 r^3?我想你真正要问的是,给定向量的平方范数,你能有效地找到立方范数吗?
  • 根据您需要的精度和 dx/dy 比率,您可以尝试泰勒级数 ( 1+x )^( 1/2 ) = 1 + ( 1/2 )*x - ( 1/8 )*x^2 + ... 其中 x = ( dx/dy )^2
  • @SteveJessop:到目前为止 3 个答案,而不是一个长凳/拆卸。我不认为人们真的有兴趣找到更快的答案,他们只是把他们能想到的任何东西扔给暴徒......

标签: c++ performance floating-point distance square-root


【解决方案1】:

怎么样

double r3 = pow(r2,1.5);

如果 sqrt 被实现为 pow 的一个特殊情况,那将为您节省一个乘法。没有什么大的计划!

如果您真的在寻找更高的效率,请考虑您是否真的需要 r^3。例如,如果您只是测试它(或从它派生的东西)以查看它是否超过某个阈值,则改为测试 r2,例如

const double r3_threshold = 9;

//don't do this
if (r3 > r3_threshold)
    ....

//do do this
const double r2_threshold = pow(r3_threshold,2./3.); 
if (r2 > r2_threshold)
    ....

这样pow 只会被调用一次,甚至可能在编译时。

编辑如果您确实需要每次都重新计算阈值,我认为关于 Q_rsqrt 的答案值得一看,并且可能值得超过这个答案

【讨论】:

  • r2*r2*r2 > r3_thresh*r3_thresh 呢?
  • @dantswain 很好,避免了pow,但它需要额外的乘法,并且代码不太清晰
  • 多出几(三)个 mults 不会比 pow 快吗?我认为可读性在这里是主观的......我通常将平方大小写为dx*dx + dy*dy < r_thresh*r_thresh;立方体版本不会让我失望。此外,如果可读性确实是一个问题,您可以将其隐藏在宏或内联中。 耸耸肩
  • 除非你的数学库真的很糟糕,否则 sqrt() 不会通过 pow(x, .5) 实现,而且它会比 pow() 快很多(IIRC 我在某些地方对此进行了测试点和 glibc sqrt() 中的 libm 大约快一个数量级)。但是,是的,我想尝试一下不会有什么坏处..
  • @dantswain 我认为 Sideshow Bob 的观点是关于重复检查相同的阈值,在这种情况下,单个 pow 会比许多 muls 更好(尽管它取决于迭代次数)。但当然,一次性检查你的 mul-version 更好。考虑到这个问题的微优化性质,我还认为可读性是次要问题。
【解决方案2】:

使用fast inverse sqrt(取Q_rsqrt函数)。

你有:

float r2;
// ... r2 gets a value
float invsqrt = Q_rsqrt(r2);
float r3 = r2*r2*invsqrt; // x*x/sqrt(x) = x*sqrt(x)

注意:对于double 类型,有一个像0x5f3759df 这样的常量,它可以帮助您编写一个同时处理double 数据类型的函数。

稍后编辑:似乎该方法已经讨论过here

后期编辑2:double 的常量在维基百科link

Lomont 指出 64 位 IEEE754 大小的“幻数” type double 是 0x5fe6ec85e7de30da,但实际上接近 0x5fe6eb50c7aa19f9.

【讨论】:

  • @SideshowBob 既然用在 Quake3 代码中,我相信它是最快的
  • 自从 Quake 3 编写以来,时代已经发生了变化。例如 SSE 有一个硬件 sqrt 指令,它更快。
  • See here 了解更多信息。
  • @IulianŞerbănoiu:它远不是最快的。它比 some 平台上的平方根指令更快,但大多数主流 CPU 可以在一条指令中计算更准确的平方根倒数估计,只需要几个周期延迟(Intel 上的rsqrtssfrsqrte 在 PPC 上,vrsqrte 在 ARM 上)。
  • r^2*r^2/sqrt(r^2) 的想法仍然有效,无论您使用 Quake 技巧还是硬件 1/sqrt 指令。
【解决方案3】:

我认为另一种看待您的问题的方式是“如何计算(或近似)sqrt(n)”。从那里你的问题将是微不足道的(n * sqrt(n))。当然,你必须定义你可以忍受多少错误。维基百科为您提供了许多选择:

http://en.wikipedia.org/wiki/Methods_of_computing_square_roots

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2021-12-18
    • 2018-01-27
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    相关资源
    最近更新 更多