加算は数学的に結合法則を保持します。
(a + b) + c = a + (b + 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
と合計され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は無効です。他のオプションが優先されます
とにかくオペランドの-funsafe-math-optimizations
順序を気にしない場合は速度を向上させることができますが、オペランドの順序が重要な場合は精度が低下しNAN
、結果が失われる可能性がありINF
ます。
Cでの浮動小数点乗算は、結合法則ではありません。
In C, Floating point multiplication is not associative.
いくつかの証拠はこのCコードにあります:
3つのランダムなfloat値を選択します。が等しくない
かどうかを確認します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
結論:
私のテストでは、ランダムに選択された3つの浮動小数点乗算値は、約70%の時間で結合しています。