C++ 中极低精度的快速单精度倒数平方根

Mar*_*ník 5 c++ performance x86 sqrt

我在 C++ 中有一行

c[i] = sqrtf(a[i]);
Run Code Online (Sandbox Code Playgroud)

和汇编代码看起来

002D11D0  vsqrtps     ymm0,ymmword ptr a (202D3380h)[eax]  
Run Code Online (Sandbox Code Playgroud)

用一条线

c[i] = 1.0f / sqrtf(a[i]);
Run Code Online (Sandbox Code Playgroud)

我有一个集会

00E71210  vrsqrtps    ymm1,ymm0  
00E71214  vmulps      ymm0,ymm1,ymm0  
00E71218  vmulps      ymm0,ymm0,ymm1  
00E7121C  vsubps      ymm0,ymm0,ymm6  
00E71220  vmulps      ymm0,ymm0,ymm1  
00E71224  vmulps      ymm0,ymm0,ymm7
Run Code Online (Sandbox Code Playgroud)

这显然是合理的,因为vrsqrtps比 快得多vsqrtps。因此,在平方根的倒数的情况下,调用不准确的函数vrsqrtps然后进行两次迭代以获得更精确的值会更快。

我的问题是: 是否可以告诉编译器不需要额外的迭代?因此汇编将不需要额外的乘法。~1.5 * 2^-12 的误差对我来说完全足够了,因为我想添加数千个这样的结果,其中许多位的准确性也会下降。我更喜欢一种不将某些汇编代码内联到 C++ 代码中的方法。

(编辑后)编译器命令行:

/GS /Qpar /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /Ox /Ob2 /sdl /Fd"Release\vc141.pdb" /Zc:inline /fp:fast /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope /arch:AVX2 /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Ot /Fp"Release\performancetest.pch" /diagnostics:classic 
Run Code Online (Sandbox Code Playgroud)

Fed*_*dor 1

恐怕没有编译器标志来强制降低倒数平方根的计算精度。

但是您可以使用内在函数轻松编写自己的函数,例如:

#include <immintrin.h>

float fast_rsqrt( float x ) {
    return _mm_cvtss_f32( _mm_rsqrt_ss( _mm_set_ss( x ) ) );
}
Run Code Online (Sandbox Code Playgroud)

这将在 x86-64 平台上的 Clang、GCC 和 MSVC 编译器中运行。最新的MSVC会为其生成这样的汇编代码:

float fast_rsqrt(float) PROC                                ; fast_rsqrt
        rsqrtss xmm1, xmm0
        movaps  xmm0, xmm1
        ret     0
float fast_rsqrt(float) ENDP                                ; fast_rsqrt
Run Code Online (Sandbox Code Playgroud)

演示: https: //gcc.godbolt.org/z/dE47M6a8x