9

我发现自己在打字

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

很多,而且我听说现代处理器具有内置的反平方根操作码。

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

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

7 回答 7

16

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

于 2012-10-16T21:26:55.407 回答
5

您可以使用此函数进行更快的逆平方根计算
维基百科上有一篇关于其工作原理的文章: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;
}
于 2018-12-22T04:58:57.003 回答
3

我不知道用于此的标准化 C API,但这并不意味着您不能使用快速逆 sqrt 指令,只要您愿意编写平台相关的内在函数

让我们以 64 位 x86 和 AVX 为例,您可以使用 _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);

同样,您可以将 ARM 上的内在vrsqrteq_f32与 NEON 一起使用。在这种情况下,SIMD 是 4 宽的,因此它会一次计算四个平方根的倒数。

#include <arm_neon.h>

...

float32x4_t sqrt_reciprocal = vrsqrteq_f32(x);

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

于 2020-06-07T01:07:07.313 回答
1

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

我使用ASMJIT即时编译您正在寻找的确切汇编操作:(RSQRTSS单精度,好的,但它应该与双精度相似)。

我的代码是这样的(参见我在另一篇文章中的回答):

   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.0/sqrt(...).

于 2019-10-30T10:10:52.867 回答
0

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

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

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

于 2012-10-16T21:42:41.693 回答
-2

如果你发现自己一遍又一遍地写同样的东西,你应该对自己思考“函数!”:

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

现在代码更加自我记录:人们不必推断 1.0 / std::sqrt(x)是平方根的倒数,他们阅读它。此外,您现在可以插入您想要的任何实现,并且每个调用站点都会自动使用更新的定义。

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

于 2012-10-16T21:41:07.887 回答
-4

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

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

于 2012-10-16T21:31:13.713 回答