相关疑难解决方法(0)

浮点除法与浮点乘法

通过编码是否有任何(非微优化)性能增益

float f1 = 200f / 2
Run Code Online (Sandbox Code Playgroud)

在比较中

float f2 = 200f * 0.5
Run Code Online (Sandbox Code Playgroud)

几年前我的一位教授告诉我,浮点除法比浮点乘法慢,但没有详细说明原因.

这句话适用于现代PC架构吗?

UPDATE1

关于评论,请同时考虑这个案例:

float f1;
float f2 = 2
float f3 = 3;
for( i =0 ; i < 1e8; i++)
{
  f1 = (i * f2 + i / f3) * 0.5; //or divide by 2.0f, respectively
}
Run Code Online (Sandbox Code Playgroud)

更新2 从评论中引用:

[我想]知道什么是算法/架构要求导致>除法在硬件上比复制要复杂得多

c++ floating-point micro-optimization

67
推荐指数
5
解决办法
5万
查看次数

Newton Raphson与SSE2 - 有人可以解释我这3行

我正在阅读这份文件:http://software.intel.com/en-us/articles/interactive-ray-tracing

我偶然发现了这三行代码:

SIMD版本已经快了很多,但我们可以做得更好.英特尔为SSE2指令集添加了快速1/sqrt(x)函数.唯一的缺点是它的精度有限.我们需要精度,所以我们使用Newton-Rhapson来改进它:

 __m128 nr = _mm_rsqrt_ps( x ); 
 __m128 muls = _mm_mul_ps( _mm_mul_ps( x, nr ), nr ); 
 result = _mm_mul_ps( _mm_mul_ps( half, nr ), _mm_sub_ps( three, muls ) ); 
Run Code Online (Sandbox Code Playgroud)

此代码假定存在名为"half"(四次0.5f)和变量"three"(四次3.0f)的__m128变量.

我知道如何使用牛顿拉夫森计算函数的零点,我知道如何使用它来计算一个数的平方根,但我看不出这些代码如何执行它.

有人可以向我解释一下吗?

c c++ math sse newtons-method

28
推荐指数
1
解决办法
2648
查看次数

是否可以滚动明显更快的sqrt版本

在我正在分析的应用程序中,我发现在某些情况下,此功能可以占用总执行时间的10%.

我已经看到多年来使用偷偷摸摸的浮点技巧进行了更快的sqrt实现的讨论,但我不知道现代CPU上是否有这样的东西已经过时了.

正在使用MSVC++ 2008编译器,以供参考......虽然我认为sqrt不会增加太多开销.

有关modf函数的类似讨论,另请参见此处.

编辑:作为参考,是一种广泛使用的方法,但它实际上更快?这些天SQRT有多少个周期?

c++ optimization sqrt

26
推荐指数
3
解决办法
3万
查看次数

快速矢量化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
查看次数

展开循环并使用矢量化进行独立求和

对于以下循环,如果我告诉它使用关联数学,例如,GCC将仅对循环进行矢量化-Ofast.

float sumf(float *x)
{
  x = (float*)__builtin_assume_aligned(x, 64);
  float sum = 0;
  for(int i=0; i<2048; i++) sum += x[i];
  return sum;
}
Run Code Online (Sandbox Code Playgroud)

这是装配 -Ofast -mavx

sumf(float*):
    vxorps  %xmm0, %xmm0, %xmm0
    leaq    8192(%rdi), %rax
.L2:
    vaddps  (%rdi), %ymm0, %ymm0
    addq    $32, %rdi
    cmpq    %rdi, %rax
    jne .L2
    vhaddps %ymm0, %ymm0, %ymm0
    vhaddps %ymm0, %ymm0, %ymm1
    vperm2f128  $1, %ymm1, %ymm1, %ymm0
    vaddps  %ymm1, %ymm0, %ymm0
    vzeroupper
    ret
Run Code Online (Sandbox Code Playgroud)

这清楚地表明循环已被矢量化.

但是这个循环也有一个依赖链.为了克服添加的延迟,我需要在x86_64上展开并执行至少三次部分和(不包括Skylake,需要展开八次并使用需要在Haswell和Broadwell上展开10次的FMA指令进行添加) .据我所知,我可以展开循环-funroll-loops.

这是装配-Ofast -mavx -funroll-loops.

sumf(float*):
    vxorps …
Run Code Online (Sandbox Code Playgroud)

c x86 gcc loop-unrolling auto-vectorization

7
推荐指数
1
解决办法
517
查看次数

准确的矢量化acosf()实现

acosf()如果平台支持融合乘加(FMA),则相对于无限精确(数学)结果,简单的实现可以轻松实现1.5 ulp的误差范围。这意味着结果与舍入至最近或偶数模式下的正确舍入结果之间的差值不得超过一个ulp。

但是,这种实现通常包括两个主要代码分支,它们将主要近似间隔[0,1]大致分为两半,如下面的示例代码所示。当针对SIMD体系结构时,这种多分支性会阻止编译器自动进行矢量化。

是否有另一种算法方法可以更轻松地实现自动矢量化,同时保持1.5 ulps的相同误差范围?可以假定为FMA提供平台支持。

/* approximate arcsin(a) on [-0.5625,+0.5625], max ulp err = 0.95080 */
float asinf_core(float a)
{
    float r, s;
    s = a * a;
    r =             0x1.a7f260p-5f;  // 5.17513156e-2
    r = fmaf (r, s, 0x1.29a5cep-6f); // 1.81669723e-2
    r = fmaf (r, s, 0x1.7f0842p-5f); // 4.67568673e-2
    r = fmaf (r, s, 0x1.329256p-4f); // 7.48465881e-2
    r = fmaf (r, s, 0x1.555728p-3f); // 1.66670144e-1
    r = r * s;
    r = fmaf (r, a, a);
    return r;
} …
Run Code Online (Sandbox Code Playgroud)

algorithm math floating-point simd

5
推荐指数
1
解决办法
192
查看次数