2012-12-17 80 views
19

加法數學持有關聯屬性:C關聯中的浮點操作?

(a + b) + c = a + (b + c) 

在一般情況下,這個屬性並不適用於浮點數,因爲它們代表在有限精度值。

作爲優化的一部分,是否允許編譯器在從C程序生成機器代碼時進行上述替換? C標準究竟在哪裏說的?

+1

對於乘法至少,看看這裏:http://stackoverflow.com/questions/6430448/why-doesnt-gcc-optimize-aaaaaa-to-aaaaaa –

回答

12

編譯器不允許執行「優化」,這將導致計算的不同的值,比所述一個根據抽象機語義計算。

5.1.2.3程序執行

[#1]本國際標準 的語義描述描述抽象機的 其優化的問題是無關緊要的行爲。

[#3]在抽象機,所有的表達式進行求值 由語義指定。

[#13]示例5浮點表達式的重新排列通常受限制,因爲精度受限於 以及範圍。實現一般是申請不了 的數學關聯規則添加或 乘法,也沒有分配規則,因爲 舍入誤差,即使沒有溢和 下溢。

在您的例子:

(a + b) + c 

甚至沒有括號:

a + b + c 

我們

+ 
/\ 
    + c 
/\ 
a b 

和編譯器來生成代碼,如果a與相加,結果與c相加。

+0

正確的理論。要回家的應用程序是:確定你的操作應該發生在什麼樣的順序上(例如,如果你想從小到大,從大到大),放置括號以滿足偏執狂,並且你可以停止擔心編譯器闖入事件重新排序。 –

+0

但請注意,儘管運算符優先級定義明確,但子表達式的評估順序未指定。換句話說,程序可以從右到左或從左到右評估這個二叉樹,它甚至不需要以一致的方式保持這個順序,也不需要記錄它。因此,如果a,b或c中含有影響結果的副作用,那麼代碼會有問題。舉例來說,c是一個修改a的函數,那麼我們無法知道結果。 – Lundin

5

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%的時間。

+0

OP詢問編譯器*是否假設float操作是關聯的,當它執行優化時。他清楚地知道他們實際上並不是。 –

+0

是的,但總是很高興看到一個證實理論的例子。 –