加法數學持有關聯屬性:C關聯中的浮點操作?
(a + b) + c = a + (b + c)
在一般情況下,這個屬性並不適用於浮點數,因爲它們代表在有限精度值。
作爲優化的一部分,是否允許編譯器在從C程序生成機器代碼時進行上述替換? C標準究竟在哪裏說的?
加法數學持有關聯屬性:C關聯中的浮點操作?
(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
與相加,結果與c
相加。
正確的理論。要回家的應用程序是:確定你的操作應該發生在什麼樣的順序上(例如,如果你想從小到大,從大到大),放置括號以滿足偏執狂,並且你可以停止擔心編譯器闖入事件重新排序。 –
但請注意,儘管運算符優先級定義明確,但子表達式的評估順序未指定。換句話說,程序可以從右到左或從左到右評估這個二叉樹,它甚至不需要以一致的方式保持這個順序,也不需要記錄它。因此,如果a,b或c中含有影響結果的副作用,那麼代碼會有問題。舉例來說,c是一個修改a的函數,那麼我們無法知道結果。 – Lundin
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%的時間。
OP詢問編譯器*是否假設float操作是關聯的,當它執行優化時。他清楚地知道他們實際上並不是。 –
是的,但總是很高興看到一個證實理論的例子。 –
對於乘法至少,看看這裏:http://stackoverflow.com/questions/6430448/why-doesnt-gcc-optimize-aaaaaa-to-aaaaaa –