是否有用于双精度平方根反比的快速 C 或 C++ 标准库函数
Is there a fast C or C++ standard library function for double precision inverse square root?
>我发现自己在打字
double foo=1.0/sqrt(...);
很多,我听说现代处理器具有内置的平方根反比操作码。
是否有 C 或 C++ 标准库平方根反比函数
- 使用双精度浮点?
- 和
1.0/sqrt(...)
一样准确吗? - 与
1.0/sqrt(...)
的结果一样快还是更快?
No.不,没有。不在C++。不。
您可以使用此函数进行更快的平方反比根计算
维基百科上有一篇关于它如何工作的文章: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;
}
提供标准化的C API,但这并不意味着您不能使用快速逆sqrt指令,只要您愿意编写依赖于平台的内部函数。
让我们以带有 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);
同样,您可以在 ARM 上使用带有 NEON 的内在vrsqrteq_f32。在本例中,SIMD 的宽度为 4,因此它将一次性计算 4 个平方根反比。
#include <arm_neon.h>
...
float32x4_t sqrt_reciprocal = vrsqrteq_f32(x);
即使每批只需要一个根值,它仍然比全平方根快。只需设置所有输入或 SIMD 寄存器的一个通道即可。这样,您就不必通过加载操作遍历内存。在x86上,这是通过_mm256_set1_ps(x)
完成的。
违反约束 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(...)
更快(虽然准确性稍低,但这是您正在谈论的内置操作所固有的)。
如果您不怕使用自己的函数,请尝试以下操作:
template <typename T>
T invsqrt(T x)
{
return 1.0 / std::sqrt(x);
}
它应该与任何现代优化编译器中的原始1.0 / std::sqrt(x)
一样快。此外,它可以与双精度或浮点一起使用。
如果你发现自己一遍又一遍地写同样的东西,你应该对自己说"函数!
double invsqrt(const double x)
{
return 1.0 / std::sqrt(x);
}
现在的代码更加自我记录:人们不必推断1.0 / std::sqrt(x)
是平方根反比,他们阅读它。此外,您现在可以插入所需的任何实现,并且每个调用站点都会自动使用更新的定义。
要回答你的问题,不,它没有 C(++) 函数,但现在你已经做了一个,如果你发现你的性能太欠缺,你可以替换你自己的定义。
为什么不试试这个呢? #define INSQRT(x) (1.0/sqrt(x))
它同样快,需要更少的打字(让你觉得它是一个函数),使用双精度,与 1/sqrt(..) 一样准确
- 库函数需要一个 std::function<void(void)>,如何传入类函数?
- 有没有一个 c++ gmp 库函数与 python gmpy2 库 divm(..) 函数相同?
- 好友库函数可以访问子数据
- 覆盖程序中的标准 C 库函数C++
- VS2017 #error: : snprintf 的宏定义与标准库函数声明冲突
- 在不使用内置库函数的情况下添加字符串,我做错了什么?
- 返回time()库函数的数据类型
- 将C++中的多个参数传递给MatLab共享库函数
- 从另一个动态链接库项目调用静态库函数
- 导入的库函数是否可以在内存中移动
- 带参数的线程调用库函数
- 在 MASM 中调用标准库函数
- char concat c++ 没有库函数
- 为什么C++ std::min_element 库函数接受采用布尔返回类型的函数对象的函子,而不是像 C 中那样的 in
- 如何在将指针传递给库函数时处理内存管理
- 使库函数模板化以避免编译器指令是否有益?
- 结构被库函数覆盖
- 如何在标准库C/C++函数中进行gdb单步执行操作
- 如何从 c++ 调用动态库函数
- 标准库函数 abs() 在不同C++编译器上的异常行为