修改函数以使用 SSE 内部函数
Modifying a function to use SSE intrinsics
我正在尝试计算根式的近似值:sqrt(i + sqrt(i + sqrt(i + ...)))
使用 SSE 以获得矢量化的加速(我还读到,SIMD 平方根函数的运行速度比先天 FPU 平方根函数快约 4.7 倍)。但是,我在矢量化版本中获得相同的功能时遇到问题;我得到的值不正确,我不确定
我原来的功能是这样的:
template <typename T>
T CalculateRadical( T tValue, T tEps = std::numeric_limits<T>::epsilon() )
{
static std::unordered_map<T,T> setResults;
auto it = setResults.find( tValue );
if( it != setResults.end() )
{
return it->second;
}
T tPrev = std::sqrt(tValue + std::sqrt(tValue)), tCurr = std::sqrt(tValue + tPrev);
// Keep iterating until we get convergence:
while( std::abs( tPrev - tCurr ) > tEps )
{
tPrev = tCurr;
tCurr = std::sqrt(tValue + tPrev);
}
setResults.insert( std::make_pair( tValue, tCurr ) );
return tCurr;
}
我编写的 SIMD 等效项(当此模板函数使用 T = float
实例化并给定tEps = 0.0005f
时)是:
// SSE intrinsics hard-coded function:
__m128 CalculateRadicals( __m128 values )
{
static std::unordered_map<float, __m128> setResults;
// Store our epsilon as a vector for quick comparison:
__declspec(align(16)) float flEps[4] = { 0.0005f, 0.0005f, 0.0005f, 0.0005f };
__m128 eps = _mm_load_ps( flEps );
union U {
__m128 vec;
float flArray[4];
};
U u;
u.vec = values;
float flFirstVal = u.flArray[0];
auto it = setResults.find( flFirstVal );
if( it != setResults.end( ) )
{
return it->second;
}
__m128 prev = _mm_sqrt_ps( _mm_add_ps( values, _mm_sqrt_ps( values ) ) );
__m128 curr = _mm_sqrt_ps( _mm_add_ps( values, prev ) );
while( _mm_movemask_ps( _mm_cmplt_ps( _mm_sub_ps( curr, prev ), eps ) ) != 0xF )
{
prev = curr;
curr = _mm_sqrt_ps( _mm_add_ps( values, prev ) );
}
setResults.insert( std::make_pair( flFirstVal, curr ) );
return curr;
}
我使用以下代码在循环中调用该函数:
long long N;
std::cin >> N;
float flExpectation = 0.0f;
long long iMultipleOf4 = (N / 4LL) * 4LL;
for( long long i = iMultipleOf4; i > 0LL; i -= 4LL )
{
__declspec(align(16)) float flArray[4] = { static_cast<float>(i - 3), static_cast<float>(i - 2), static_cast<float>(i - 1), static_cast<float>(i) };
__m128 arg = _mm_load_ps( flArray );
__m128 vec = CalculateRadicals( arg );
float flSum = Sum( vec );
flExpectation += flSum;
}
for( long long i = iMultipleOf4; i < N; ++i )
{
flExpectation += CalculateRadical( static_cast<float>(i), 0.0005f );
}
flExpectation /= N;
我得到以下输入5
输出:
With SSE version: 2.20873
With FPU verison: 1.69647
差异从何而来,我在 SIMD 等效项中做错了什么?
编辑:我已经意识到Sum
函数在这里是相关的:
float Sum( __m128 vec1 )
{
float flTemp[4];
_mm_storeu_ps( flTemp, vec1 );
return flTemp[0] + flTemp[1] + flTemp[2] + flTemp[3];
}
SSE 内部函数有时可能非常乏味......
但不是在这里。你刚刚搞砸了你的循环:
for( long long i = iMultipleOf4; i > 0LL; i -= 4LL )
我怀疑它是否按照您的预期行事。如果 iMultipleOf4
为 4,则函数将使用 4,3,2,1 而不是 0 进行计算。然后你的第二个循环用 4 重做计算。
这两个函数为我提供了相同的结果,并且循环在校正后给出了相同的flExpectation
。虽然仍然有一点差异,可能是因为 FPU 在计算方式上略有不同。
相关文章:
- C++ SSE 内部函数:将结果存储在变量中
- C++代码停止工作错误使用cout内部函数
- 为什么从具有较大阵列的 SIMD 内部函数中获得的相对加速比标量更大?
- 使用英特尔内部函数 (AVX) 中的混合说明
- 使用SSE内部函数复制少量数据时出现问题
- 使用 SSE 内部函数存储四个 16 位整数
- 使用SSE内部函数编译一个简单的c++程序
- 了解SSE的内部函数如何使用内存
- 性能 AVX/SSE 程序集与内部函数
- 使用SSE内部函数将布尔数组(8字节布尔)转换为int或char
- 修改函数以使用 SSE 内部函数
- 将特定的 SSE 内部函数转换为 NEON 内部函数
- SSE 内部函数:屏蔽浮点数并使用按位 and
- 如何将此代码重写为 sse 内部函数
- SSE 内部函数位向右移动
- 将SSE内部函数转换为可读的C/C++代码
- SSE内部函数导致正常浮点运算返回-1.#INV
- 强制AVX内部函数使用SSE指令
- 使用sse和avx内部函数将一组打包的单值添加到一个值中
- 编译器如何处理SSE(或任何)内部函数