相关疑难解决方法(0)

为什么SSE标量sqrt(x)比rsqrt(x)*x慢?

我一直在英特尔Core Duo上分析我们的一些核心数学,并且在研究平方根的各种方法时,我注意到一些奇怪的事情:使用SSE标量操作,采用倒数平方根并乘以它更快获取sqrt,而不是使用本机sqrt操作码!

我正在测试它的循环类似于:

inline float TestSqrtFunction( float in );

void TestFunc()
{
  #define ARRAYSIZE 4096
  #define NUMITERS 16386
  float flIn[ ARRAYSIZE ]; // filled with random numbers ( 0 .. 2^22 )
  float flOut [ ARRAYSIZE ]; // filled with 0 to force fetch into L1 cache

  cyclecounter.Start();
  for ( int i = 0 ; i < NUMITERS ; ++i )
    for ( int j = 0 ; j < ARRAYSIZE ; ++j )
    {
       flOut[j] = TestSqrtFunction( flIn[j] ); …
Run Code Online (Sandbox Code Playgroud)

floating-point performance x86 assembly sse

106
推荐指数
4
解决办法
4万
查看次数

在C++中最快的正弦,余弦和平方根的实现(不需要太精确)

我正在谷歌搜索过去一小时的问题,但只有泰勒系列或一些示例代码的要点太慢或根本不编译.好吧,我发现谷歌的答案大多是"Google it,它已经被问到了",但遗憾的是它不是 ......

我在低端Pentium 4上分析我的游戏,发现大约85%的执行时间浪费在计算窦,cosinus和平方根(来自Visual Studio中的标准C++库)上,这似乎与CPU密切相关(在我的I7上,相同的功能只有5%的执行时间,并且游戏更快了waaaaaaaaaa).我不能优化这三个函数,也不能在一次传递中计算正弦和余弦(相互依赖),但我不需要太精确的模拟结果,所以我可以使用更快的逼近.

那么,问题是:在C++中计算float的正弦,余弦和平方根的最快方法是什么?

编辑 查找表更加痛苦,因为在现代CPU上产生的Cache Miss比Taylor系列更昂贵.这些天CPU很快,而缓存则不然.

我犯了一个错误,我虽然需要为Taylor系列计算几个阶乘,我现在看到它们可以实现为常量.

所以更新的问题是:对于平方根还有任何快速优化吗?

EDIT2

我使用平方根计算距离,而不是规范化 - 不能使用快速反平方根算法(如评论中所指出:http://en.wikipedia.org/wiki/Fast_inverse_square_root

EDIT3

我也无法在平方距离上操作,我需要精确的距离进行计算

c++ math optimization trigonometry

34
推荐指数
10
解决办法
6万
查看次数

为什么GCC或Clang在使用快速数学时不能优化1指令的倒数

有谁知道为什么GCC/Clang不会在下面的代码示例中优化函数test1,只是在使用fast-math选项时只使用RCPPS指令?是否有另一个编译器标志会生成此代码?

typedef float float4 __attribute__((vector_size(16)));

float4 test1(float4 v)
{
    return 1.0f / v;
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看已编译的输出:https://goo.gl/jXsqat

c++ sse simd compiler-optimization fast-math

15
推荐指数
2
解决办法
1209
查看次数

快速矢量化rsqrt和SSE/AVX的倒数取决于精度

假设有必要计算打包浮点数据的倒数或倒数平方根.两者都可以轻松完成:

__m128 recip_float4_ieee(__m128 x) { return _mm_div_ps(_mm_set1_ps(1.0f), x); }
__m128 rsqrt_float4_ieee(__m128 x) { return _mm_div_ps(_mm_set1_ps(1.0f), _mm_sqrt_ps(x)); }
Run Code Online (Sandbox Code Playgroud)

这种方法效果很好但很慢:根据指南,它们在Sandy Bridge上进行了14次和28次循环(吞吐量).对应的AVX版本在Haswell上几乎占用相同的时间.

另一方面,可以使用以下版本:

__m128 recip_float4_half(__m128 x) { return _mm_rcp_ps(x); }
__m128 rsqrt_float4_half(__m128 x) { return _mm_rsqrt_ps(x); }
Run Code Online (Sandbox Code Playgroud)

它们只需要一到两个时间周期(吞吐量),从而大大提升了性能.但是,它们非常接近:它们产生的结果相对误差小于1.5*2 ^ -12.鉴于单精度浮点数的机器epsilon是2 ^?24,我们可以说这种近似具有大约一半的精度.

似乎可以添加Newton-Raphson迭代以产生具有精度的结果(可能不像IEEE标准所要求的那样精确),参见GCC,ICC,LLVM上的讨论.理论上,相同的方法可用于双精度值,产生精度或精度或精度.

我有兴趣为float和double数据类型以及所有(half,single,double)精度实现此方法的实现.处理特殊情况(除以零,sqrt(-1),inf/nan等)不是必需的.此外,我不清楚这些例程中的哪一个比普通的IEEE编译解决方案更快,哪个更慢.

以下是对答案的一些小限制,请:

  1. 在代码示例中使用内在函数.程序集依赖于编译器,因此不太有用.
  2. 对函数使用类似的命名约定.
  3. 实现例程,将单个SSE/AVX寄存器包含密集打包的float/double值作为输入.如果有相当大的性能提升,你也可以发布几个寄存器作为输入的例程(两个reg可能是可行的).
  4. 如果两个SSE/AVX版本绝对等于将_mm更改为_mm256,则不要发布它们,反之亦然.

欢迎任何性能评估,测量和讨论.

摘要

以下是具有一次NR迭代的单精度浮点数的版本:

__m128 recip_float4_single(__m128 x) {
  __m128 res = _mm_rcp_ps(x);
  __m128 muls …
Run Code Online (Sandbox Code Playgroud)

performance sse simd avx

12
推荐指数
1
解决办法
4202
查看次数