双和ffast数学的自动矢量化

问题描述 投票:5回答:3

为什么使用-ffast-math和g ++来使用doubles来实现循环的矢量化是强制性的?我不喜欢-ffast-math,因为我不想失去精确度。

gcc g++ double vectorization fast-math
3个回答
8
投票

使用-ffast-math你不一定会失去精确度。它只影响NaNInf等的处理以及执行操作的顺序。

如果您有一段特定的代码,您不希望GCC重新排序或简化计算,则可以使用asm语句将变量标记为正在使用。

例如,以下代码对f执行舍入操作。然而,两个f += gf -= 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
投票

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

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

基本上归结为浮点环境,矢量化代码可能与非矢量化代码的环境不同,有时候以重要的方式,如果差异对你不重要,像

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

但首先要查看这些选项并确保它们不会影响程序的正确性。 -ffinite-math-only也可能有所帮助


0
投票

Because -ffast-math enables operands reordering which allows many code to be vectorized.

例如计算这个

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

编译器需要在没有-ffast-math的情况下顺序执行添加,因为浮点数学既不是可交换的也不是关联的。

这就是没有why compilers can't optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)-ffast-math的原因

这意味着除非你有非常有效的水平向量加法,否则没有矢量化可用。

但是,如果-ffast-math启用,表达式可以计算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。自动矢量

它可以通过gcc中的-fassociative-math标志启用

Further readings

© www.soinside.com 2019 - 2024. All rights reserved.