Операции с плавающей запятой в C-ассоциативном?
Дополнение математически содержит ассоциативное свойство:
(a + b) + c = a + (b + c)
В общем случае это свойство не выполняется для чисел с плавающей запятой, поскольку они представляют значения с конечной точностью.
Можно ли компилятору разрешить эту замену при генерации машинного кода из программы C как часть оптимизации? Где он точно говорит в стандарте C?
Ответы
Ответ 1
Компилятору не разрешено выполнять "оптимизации", что приведет к вычислению другого значения, чем вычисляемое по семантике абстрактной машины.
5.1.2.3 Выполнение программы
[# 1] Семантические описания в этом Интернационале Стандарт описывает поведение абстрактной машины в какие вопросы оптимизации не имеют значения.
[# 3] В абстрактной машине все выражения оцениваются как определено семантикой.
[# 13] ПРИМЕР 5 Перестановка для выражений с плавающей точкой часто ограничивается из-за ограничений точности а также диапазон. Реализация не может в целом применяться математические ассоциативные правила для добавления или умножения или распределения, из-за ошибка округления, даже при отсутствии переполнения и опустошения.
В вашем примере:
(a + b) + c
или даже без круглых скобок:
a + b + c
имеем
+
/ \
+ c
/ \
a b
и компилятор должен генерировать код, как если бы a
суммируется с b
, и результат суммируется с c
.
Ответ 2
Умножение с плавающей запятой в 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% случаев.