C++ 是否有快速C或C++;双精度逆平方根的标准库函数?
我发现自己在打字C++ 是否有快速C或C++;双精度逆平方根的标准库函数?,c++,c,double,sqrt,C++,C,Double,Sqrt,我发现自己在打字 double foo=1.0/sqrt(...); 很多,我听说现代处理器有内置的平方根逆操作码 是否存在C或C++标准库反平方根函数 使用双精度浮点 精确到1.0/sqrt(…) 与1.0/sqrt(…)的结果一样快或更快 不,不,没有。不在C++中。没有。为什么不试试这个#定义INSQRT(x)(1.0/sqrt(x)) 它同样快速,需要更少的输入(让你感觉它是一个函数),使用双精度,精确到1/sqrt(…)如果你发现自己一遍又一遍地写着同样的东西,你应该想一想“函数!”
double foo=1.0/sqrt(...);
很多,我听说现代处理器有内置的平方根逆操作码
是否存在C或C++标准库反平方根函数
1.0/sqrt(…)
1.0/sqrt(…)
的结果一样快或更快不,不,没有。不在C++中。没有。为什么不试试这个<代码>#定义INSQRT(x)(1.0/sqrt(x))
它同样快速,需要更少的输入(让你感觉它是一个函数),使用双精度,精确到1/sqrt(…)如果你发现自己一遍又一遍地写着同样的东西,你应该想一想“函数!”: 现在,代码更加自我记录:人们不必推断
1.0/std::sqrt(x)
是平方根的倒数,而是阅读它。此外,您现在可以插入任何您想要的实现,并且每个调用站点都会自动使用更新的定义
要回答您的问题,没有,它没有C(++)函数,但是现在您已经制作了一个,如果您发现您的性能太差,您可以替换您自己的定义。如果您不怕使用自己的函数,请尝试以下操作:
template <typename T>
T invsqrt(T x)
{
return 1.0 / std::sqrt(x);
}
模板
T invsqrt(T x)
{
返回1.0/std::sqrt(x);
}
它应该与任何现代优化编译器中的原始
1.0/std::sqrt(x)
一样快。此外,它还可以用于双精度或浮点。您可以使用此函数进行更快的平方根求逆运算维基百科上有一篇文章介绍了它的工作原理:
还有这个算法的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;
}
违反限制1。二,。(这也不是标准的),但它仍然可以帮助人们浏览 我曾经及时编译过您想要的确切汇编操作:
RSQRTSS
(单精度,可以,但应该与双精度类似)
我的代码如下(参见我在另一篇文章中的代码):
typedef float(*JITFunc)();
JITFunc func;
asmjit::jit运行时jit_运行时;
asmjit::代码持有者代码;
init(jit_runtime.getCodeInfo());
asmjit::x86编译器cc(&code);
cc.addFunc(asmjit::functSignature0());
浮动值=2.71;//一些示例值。
asmjit::X86Xmm x=cc.newXmm();
uint32\u t*i=重新解释铸件和价值;
cc.mov(asmjit::x86::eax,i[0]);
cc.movd(x,asmjit::x86::eax);
抄送rsqrtss(x,x);//asm功能。
cc.ret(x);
cc.endFunc();
cc.finalize();
jit_runtime.add(&func,&code);
//现在,func()可以用作rsqrt(value)的结果。
如果只执行一次JIT编译部分,稍后使用不同的值调用它,那么这应该比
1.0/sqrt(…)
更快(虽然精度稍低,但这是您所说的内置操作固有的),但这并不意味着您不能使用快速反向sqrt指令,只要您愿意编写平台相关的内部函数
以64位x86和AVX为例,您可以使用
近似平方根的倒数。或者更具体地说:使用SIMD,一次执行8个平方根
#include <immintrin.h>
...
float inputs[8] = { ... } __attribute__ ((aligned (32)));
__m256 input = _mm256_load_ps(inputs);
__m256 invroot = _mm256_rsqrt_ps(input);
#包括
...
浮点输入[8]={…}uuuuu属性_uuu((对齐(32));
__m256输入=mm256_load_ps(输入);
__m256 invroot=_mm256_rsqrt_ps(输入);
类似地,您可以将ARM上的固有功能与NEON一起使用。在本例中,SIMD的宽度为4,因此它将在一次go中计算四个平方反根
#include <arm_neon.h>
...
float32x4_t sqrt_reciprocal = vrsqrteq_f32(x);
#包括
...
浮动32x4_t sqrt_倒数=vrsqrteq_f32(x);
即使每批只需要一个根值,它仍然比完整的平方根快。只需在SIMD寄存器的所有或一个通道中设置输入。这样,您就不必通过加载操作来遍历内存。在x86上通过
\u mm256\u set1\u ps(x)
@Pherric Oxide:这是平方反比,而不是平方反比。#定义INSQRT(x)(1.0/sqrt(x))您听说过的内置平方反比指令是近似值,不像sqrt
那样精确。马克·兰瑟姆:这基本上就是我想要的答案。我没有投反对票,但当函数可以运行时,这里的宏没有用。(你甚至自己说过:让它感觉像一个函数?只是真正地做一个函数。)@gmannick我没有将它转换成函数的原因是,因为问题清楚地提到:“与1.0/sqrt(…)的结果一样快或更快。”。将其变为函数将增加额外的开销,使“语句”1.0/sqrt(…)变慢。过去十年中的任何编译器都不会这样做。@PrototypeStark:请提供基准来支持您的说法,即使用真正的函数会变慢。在没有证据表明宏需要满足某些标准的情况下,可以安全地避免使用宏。也就是说,我总是随身携带我的#define isNaN(x)((x)!=(x))
;有时候感觉这么糟糕真是太好了。这违反了问题中的第三条规则!很抱歉,据我所知,它应该“一样快”。阅读以了解为什么模板函数应该比非模板代码慢。此外,如果在gcc中启用-ffast math
,它将使用平方根反比的近似值。这将确保它和普通平方根一样快。@PrototypeStark:因为它不像或那样简单。一个是类型检查、可调试、可作用域、可重载、对其参数进行一次计算等(函数的所有特性),另一个不是。这是一个单一的否决票,这不是世界末日;我理解没有从当事人自己那里得到一个理由是令人沮丧的,但事实就是如此。我认为阅读1.0/sqrt(x)
as更容易
#include <immintrin.h>
...
float inputs[8] = { ... } __attribute__ ((aligned (32)));
__m256 input = _mm256_load_ps(inputs);
__m256 invroot = _mm256_rsqrt_ps(input);
#include <arm_neon.h>
...
float32x4_t sqrt_reciprocal = vrsqrteq_f32(x);