代码之家  ›  专栏  ›  技术社区  ›  Ruggero Turra

双快速数学的自动矢量化

  •  5
  • Ruggero Turra  · 技术社区  · 14 年前

    为什么必须使用 -ffast-math 用G++实现循环的矢量化 double S?我不喜欢 FFAST数学 因为我不想失去精确性。

    3 回复  |  直到 6 年前
        1
  •  8
  •   sam hocevar    13 年前

    你不一定会失去精确性 -ffast-math . 它只影响 NaN , Inf 等等,以及执行操作的顺序。

    如果您有一段不希望GCC重新排序或简化计算的特定代码,可以使用 asm 语句。

    例如,以下代码对 f . 然而,这两个 f += g f -= g GCC可能会优化运营:

    static double moo(double f, double g)                                      
    {                                                                          
        g *= 4503599627370496.0; // 2 ** 52                                    
        f += g;                                                                
        f -= g;                                                                
        return f;                                                            
    }                                                                     
    

    在x86_64上,您可以使用这个 ASM 指示GCC不进行优化的声明:

    static double moo(double f, double g)                                      
    {                                                                          
        g *= 4503599627370496.0; // 2 ** 52                                    
        f += g;                                                                
        __asm__("" : "+x" (f));
        f -= g;
        return f;
    }
    

    不幸的是,您需要为每个体系结构调整这一点。在PowerPC上使用 +f 而不是 +x .

        2
  •  2
  •   Spudd86    14 年前

    很可能是因为矢量化意味着您可能有不同的结果,或者可能意味着您错过了浮点信号/异常。

    如果您编译的是32位x86,那么gcc和g++默认使用x87进行浮点运算,而64位的gcc和g++默认使用sse,但是x87可以并且将为相同的计算生成不同的值,因此,如果不能保证得到相同的结果,那么g++不太可能考虑向量化,除非使用-ffast math或som它打开的标志中的e。

    基本上,归根结底,矢量化代码的浮点环境可能与非矢量化代码的浮点环境不同,有时在一些重要的方面,如果差异对您不重要,比如

    -fno-math-errno -fno-trapping-math -fno-signaling-nans -fno-rounding-math
    

    但首先要查找这些选项,确保它们不会影响程序的正确性。 -ffinite-math-only 也可以帮助

        3
  •  0
  •   phuclv    6 年前

    因为 -ffast-math 使能够 操作数重新排序 这使得许多代码可以向量化。

    例如计算这个

    sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + … a[99]
    

    编译器是 必修的 添加 顺序地 没有 FFAST数学 因为浮点数学既不是交换的也不是结合的。

    这也是原因 why compilers can't optimize a*a*a*a*a*a to (a*a*a)*(a*a*a) 没有 FFAST数学

    这意味着没有矢量化可用,除非您有非常有效的水平矢量添加。

    但是如果 FFAST数学 如果启用,则可以计算表达式 like this (看 A7. Auto-Vectorization )

    sum0 = a[0] + a[4] + a[ 8] + … a[96]
    sum1 = a[1] + a[5] + a[ 9] + … a[97]
    sum2 = a[2] + a[6] + a[10] + … a[98]
    sum3 = a[3] + a[7] + a[11] + … a[99]
    sum’ = sum0 + sum1 + sum2 + sum3
    

    现在,编译器可以通过并行添加每一列,然后在末尾进行水平添加,轻松地将其向量化。

    sum’ == sum ?只有 (a[0]+a[4]+…) + (a[1]+a[5]+…) + (a[2]+a[6]+…) + ([a[3]+a[7]+…) == a[0] + a[1] + a[2] + … 这在关联性下是成立的,而浮动不坚持,所有的时间。指定 /fp:fast 对于这个简单的计算,允许编译器将代码转换为运行速度快4倍。

    Do You Prefer Fast or Precise? -A7。自动矢量化

    它可以通过 -fassociative-math 海湾合作委员会旗

    进一步阅读

    推荐文章