[英]Are floating point operations in C associative?
添加在數學上保持關聯屬性:
(a + b) + c = a + (b + c)
在一般情況下,此屬性不適用於浮點數,因為它們表示有限精度的值。
作為優化的一部分,是否允許編譯器在從C程序生成機器代碼時進行上述替換? 它在C標准中的確切位置在哪里?
不允許編譯器執行“優化”,這將導致計算的值不同於根據抽象機器語義計算的值。
5.1.2.3程序執行
[#1]本國際標准中的語義描述描述了抽象機器的行為,其中優化問題無關緊要。
[#3]在抽象機器中,所有表達式都按語義指定進行計算。
[#13]示例5由於精度和范圍的限制,浮點表達式的重排通常受到限制。 即使在沒有溢出和下溢的情況下,由於舍入誤差,實現通常也不能應用加法或乘法的數學關聯規則,也不能應用分布規則。
在你的例子中:
(a + b) + c
甚至沒有括號:
a + b + c
我們有
+
/ \
+ c
/ \
a b
並且編譯器需要生成代碼,好像a
與b
相加,結果與c
相加。
您可以使浮點運算與gcc選項相關聯:
-funsafe-math-optimizations -O2
例:
double test (double a, double b, double c) {
return (a + b + c) * (a + (b + c));
}
這減少為:
double temp = a + (b + c);
return temp * temp;
類似地, (a + b + c) - (a + (b + c))
減少到零,忽略了INF
和NAN
的可能性。
如果我用-fassociative-math -O2
編譯,我得到了奇怪的消息:
警告:-fassociative-math disabled; 其他選項優先
如果您不關心操作數的順序, -funsafe-math-optimizations
可以提高速度,但如果操作數的順序很重要,它可能會導致精度損失,並且您可能會丟失NAN
和INF
結果。
C中的浮點乘法不是關聯的。
In C, Floating point multiplication is not associative.
一些證據是這個C代碼:
選擇三個隨機浮點值。
檢查a*(b*c)
是否不等於(a*b)*c
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
using namespace std;
int main() {
int counter = 0;
srand(time(NULL));
while(counter++ < 10){
float a = rand() / 100000;
float b = rand() / 100000;
float c = rand() / 100000;
if (a*(b*c) != (a*b)*c){
printf("Not equal\n");
}
}
printf("DONE");
return 0;
}
程序打印:
Not equal
Not equal
Not equal
Not equal
DONE
RUN FINISHED; exit value 0; real time: 10ms; user: 0ms; system: 0ms
結論:
對於我的測試,三個隨機選擇的浮點乘法值在大約70%的時間內是關聯的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.