双精度平方根有快速C或C ++标准库函数吗?

时间:2012-10-16 21:25:44

标签: c++ c double sqrt

我发现自己在打字

double foo=1.0/sqrt(...);

很多,我听说现代处理器内置了反平方根操作码。

是否有C或C ++标准库的反平方根函数

  1. 使用双精度浮点?
  2. 1.0/sqrt(...)一样准确吗?
  3. 1.0/sqrt(...)的结果一样快或更快?

7 个答案:

答案 0 :(得分:10)

没有。不,没有。不是在C ++中。不。

答案 1 :(得分:1)

您可以使用此功能进行更快的平方根逆计算
维基百科上有一篇有关其工作原理的文章:https://en.wikipedia.org/wiki/Fast_inverse_square_root
还有该算法的C版本。

float invSqrt( float number ){
    union {
        float f;
        uint32_t i;
    } conv;

    float x2;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    conv.f  = number;
    conv.i  = 0x5f3759df - ( conv.i >> 1 );
    conv.f  = conv.f * ( threehalfs - ( x2 * conv.f * conv.f ) );
    return conv.f;
}

答案 2 :(得分:1)

违反约束1.和2.(这也不是标准的),但是它仍然可以帮助某人浏览...

我使用ASMJIT即时编译了您要查找的确切汇编操作:RSQRTSS(单精度,可以,但应该与double相似)。

我的代码是这样的(另请参阅我的answer在另外的帖子中):

   typedef float(*JITFunc)();

   JITFunc func;
   asmjit::JitRuntime jit_runtime;
   asmjit::CodeHolder code;
   code.init(jit_runtime.getCodeInfo());

   asmjit::X86Compiler cc(&code);
   cc.addFunc(asmjit::FuncSignature0<float>());

   float value = 2.71; // Some example value.
   asmjit::X86Xmm x = cc.newXmm();
   uint32_t *i = reinterpret_cast<uint32_t*>(&value);
   cc.mov(asmjit::x86::eax, i[0]);
   cc.movd(x, asmjit::x86::eax);

   cc.rsqrtss(x, x);   // THE asm function.

   cc.ret(x);

   cc.endFunc();
   cc.finalize();

   jit_runtime.add(&func, &code);

   // Now, func() can be used as the result to rsqrt(value).

如果您只执行一次JIT编译部分,然后以不同的值调用它,那么它应该比{{1更快(尽管精度稍差,但这是您正在谈论的内置操作所固有的)) }}。

答案 3 :(得分:1)

我不知道为此使用标准化的C API,但这并不意味着您只要愿意编写依赖于平台的内在函数,就不能使用快速反sqrt指令。 / p>

以AVX的64位x86为例,您可以在其中使用 _mm256_rsqrt_ps()来近似平方根的倒数。或者更具体地说:使用SIMD,一次完成8个平方根。

#include <immintrin.h>

...

float inputs[8] = { ... } __attribute__ ((aligned (32)));
__m256 input = _mm256_load_ps(inputs);
__m256 invroot = _mm256_rsqrt_ps(input);

类似地,您可以在带有NEON的ARM上使用固有的vrsqrteq_f32。在这种情况下,SIMD为4宽,因此它将一次计算四个逆平方根。

#include <arm_neon.h>

...

float32x4_t sqrt_reciprocal = vrsqrteq_f32(x);

即使每批只需要一个根值,它仍然比全平方根更快。只需在SIMD寄存器的全部或一个通道中设置输入即可。这样,您将不必通过加载操作来遍历内存。在通过_mm256_set1_ps(x)完成的x86上。

答案 4 :(得分:0)

如果您不怕使用自己的功能,请尝试以下操作:

template <typename T>
T invsqrt(T x)
{
    return 1.0 / std::sqrt(x);
}

它应该与任何现代优化的编译器中的原始1.0 / std::sqrt(x)一样快。此外,它可以与双打或浮动一起使用。

答案 5 :(得分:-1)

为什么不尝试这个? #define INSQRT(x) (1.0/sqrt(x))

它同样快,需要较少的打字(让你觉得它是一个函数),使用双精度,准确到1 / sqrt(..)

答案 6 :(得分:-1)

如果你发现自己一遍又一遍地写同样的东西,你应该自己想一想“功能!”:

double invsqrt(const double x)
{
    return 1.0 / std::sqrt(x);
}

现在代码更加自我记录:人们不必演绎 1.0 / std::sqrt(x)是平方根,他们它。此外,您现在可以插入所需的任何实现,并且每个呼叫站点自动使用更新的定义。

要回答你的问题,不,它没有C(++)函数,但是现在如果你发现你的表现太缺乏了,你可以用自己的定义代替。