Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于GCC的联想数学_C_Gcc_Floating Point_Precision - Fatal编程技术网

基于GCC的联想数学

基于GCC的联想数学,c,gcc,floating-point,precision,C,Gcc,Floating Point,Precision,我在C中创建了一个数据类型。我尝试了使用GCC的-Ofast,发现它的速度非常快(例如,使用-O3的速度为1.5s,使用-Ofast的速度为0.3s),但结果是假的。我把这个问题归结为社交数学。我很惊讶这不起作用,因为我明确定义了操作的关联性。例如,在下面的代码中,我只使用了括号 static inline doublefloat two_sum(const float a, const float b) { float s = a + b; float v =

我在C中创建了一个数据类型。我尝试了使用GCC的
-Ofast
,发现它的速度非常快(例如,使用
-O3
的速度为1.5s,使用
-Ofast
的速度为0.3s),但结果是假的。我把这个问题归结为社交数学。我很惊讶这不起作用,因为我明确定义了操作的关联性。例如,在下面的代码中,我只使用了括号

static inline doublefloat two_sum(const float a, const float b) {
        float s = a + b;
        float v = s - a;
        float e = (a - (s - v)) + (b - v);
        return (doublefloat){s, e};
}
因此,我不希望GCC会改变,例如
(a-(s-v))
((a+v)-s)
,即使使用
-fassocialmath
。那么,为什么使用
-fassocialmath
(而且速度更快)得出的结果会如此错误呢

我用MSVC尝试了
/fp:fast
(在将代码转换为C++之后),结果是正确的,但并不比
/fp:precise

根据GCC手册中关于
-fassocialative math
的规定

允许在一系列浮点运算中重新关联操作数。这违反了ISOC和C++语言标准,可能会改变计算结果。注:重新订购也可能会更改零的符号 as忽略NAN并禁止或创建下溢或上溢(因此不能用于依赖舍入行为的代码,如“(x+2^52)-2^52)。也可以对浮点比较进行重新排序,因此可能不会 当需要有序比较时使用。此选项要求-fno有符号零和-fno陷阱数学都有效。此外,它对-fno陷阱数学没有多大意义

编辑:

我使用整数(有符号和无符号)和浮点进行了一些测试,以检查GCC是否简化了关联操作

//test1.c
unsigned foosu(unsigned a, unsigned b, unsigned c) { return (a + c) - b; }
signed   fooss(signed   a, signed   b, signed   c) { return (a + c) - b; }
float    foosf(float    a, float    b, float    c) { return (a + c) - b; }
unsigned foomu(unsigned a, unsigned b, unsigned c) { return a*a*a*a*a*a; }
signed   fooms(signed   a, signed   b, signed   c) { return a*a*a*a*a*a; }
float    foomf(float    a, float    b, float    c) { return a*a*a*a*a*a; }

我遵守了O3和Ofast的要求,我查看了生成的程序集,这就是我观察到的

  • 无符号:加法和乘法的代码相同(减少为三次乘法)
  • 有符号:加法的代码不相同,但乘法的代码相同(减少为三次乘法)
  • 浮点:与
    -O3
    的加法或乘法的代码不相同,但与
    -Ofast
    的加法相同,乘法几乎相同,仅使用三次乘法
由此我得出结论

  • 如果一个操作是关联的,那么GCC将简化它,不管它选择什么,这样
    a-(b-c)
    就可以变成
    (a+c)-b
  • 无符号加法和乘法是结合的
  • 有符号加法不是关联的
  • 有符号乘法是结合的
  • 使用
    -fassocialative math
    时,整数和浮点的乘法简化为三次
  • -fassocialative math
    使浮点加法和乘法具有关联性
换句话说,GCC做了我没有预料到的事情,它将
(a-(s-v))
转换为
((a+v)-s)

人们可能会认为这在
-fassocialmath
中很明显,但在某些情况下,程序员可能希望浮点在一种情况下是关联的,而在另一种情况下是非关联的。但如果这样做,双浮点就不能在同一个模块中使用。因此,唯一的选择是将关联浮点函数n一个模块和另一个模块中的非关联浮点函数,并将它们编译成单独的对象文件

我很惊讶这不起作用,因为我显式地定义了操作的关联性

这正是
-fasociative math
所做的:它忽略了程序定义的顺序(与没有括号的定义相同)通常,对于二重加法,错误项被计算为0,因为如果浮点运算是关联的,它将等于0。
e=0;
e=(a-…;
快得多,但当然,这是错误的

在C99标准中,6.5.6:1中的以下语法规则意味着
x+y+z
只能解析为
(x+y)+z

additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression 加法表达式: 乘法表达式 加法表达式+乘法表达式 加法表达式-乘法表达式 显式括号和对中间左值的赋值并不妨碍
-fassocialative math
的工作。即使没有括号和赋值,顺序也是定义的(如果是一系列的加减法,从左到右),您告诉编译器忽略已定义的顺序。事实上,在应用优化的中间表示法上,我怀疑信息是否仍然存在,顺序是由中间赋值、括号还是语法强加的

您可以尝试将希望按照C标准规定的顺序编译的所有函数放在不使用
-fasociative math
编译的同一个编译单元中,或者在整个程序中完全避免使用此标志。如果您坚持在使用
-f编译的编译单元中保留双加关联数学
,您可以尝试使用
volatile
变量,但是
volatile
类型限定符只将访问左值作为一个可观察的事件,它不会强制进行正确的计算。

当然没有人会将
(a-(s-v))
重新解释为
((a-s)-v)
。这不是这种“关联性”所指的。
v=(a+b)-a
被简化为
b
,正如文档所说。这正是代码的类型 additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression