¿Las operaciones de punto flotante en C son asociativas?
math floating-point (3)
El compilador no tiene permitido realizar "optimizaciones", lo que daría como resultado un valor diferente calculado, que el calculado de acuerdo con la semántica de la máquina abstracta.
5.1.2.3 Ejecución del programa
[# 1] Las descripciones semánticas en esta Norma Internacional describen el comportamiento de una máquina abstracta en la que los problemas de optimización son irrelevantes.
[# 3] En la máquina abstracta, todas las expresiones se evalúan según lo especificado por la semántica.
[# 13] EJEMPLO 5 La reorganización de las expresiones de punto flotante a menudo está restringida debido a las limitaciones de precisión y rango. La implementación generalmente no puede aplicar las reglas asociativas matemáticas para la suma o la multiplicación, ni la regla distributiva, debido a un error de redondeo, incluso en ausencia de desbordamiento y subdesbordamiento.
En tu ejemplo:
(a + b) + c
O incluso sin los paréntesis:
a + b + c
tenemos
+
/ /
+ c
/ /
a b
y el compilador debe generar código como si a
se sumara con b
y el resultado se sumara con c
.
La adición posee matemáticamente la propiedad asociativa:
(a + b) + c = a + (b + c)
En el caso general, esta propiedad no se aplica a los números de punto flotante porque representan valores con una precisión finita.
¿Se permite a un compilador realizar la sustitución anterior cuando se genera un código de máquina desde un programa C como parte de una optimización? ¿Dónde dice exactamente en el estándar C?
Puede hacer que las operaciones de punto flotante sean asociativas con las opciones de gcc:
-funsafe-math-optimizations -O2
Ejemplo: prueba doble (doble a, doble b, doble c) {
retorno (a + b + c) * (a + (b + c)); }
Esto se reduce a: temperatura doble = a + (b + c); temp temp * temp;
De manera similar, (a + b + c) - (a + (b + c)) se reduce a cero, ignorando la posibilidad de INF y NAN.
Si compilo con -fasociative-math -O2 en su lugar, recibo el mensaje extraño: "advertencia: -fassociative-math desactivado; otras opciones tienen prioridad".
Las optimizaciones de -funsafe-math pueden mejorar la velocidad si de todos modos no le importa el orden de los operandos, pero puede causar pérdida de precisión si el orden de los operandos es importante, y puede perder los resultados NAN e INF.
La multiplicación de coma flotante en C no es asociativa.
In C, Floating point multiplication is not associative.
Alguna evidencia está con este código C:
Elige tres valores flotantes aleatorios.
Compruebe si a*(b*c)
no es igual a (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;
}
El programa imprime:
Not equal
Not equal
Not equal
Not equal
DONE
RUN FINISHED; exit value 0; real time: 10ms; user: 0ms; system: 0ms
Conclusión:
Para mi prueba, tres valores de multiplicación de punto flotante seleccionados al azar son asociativos aproximadamente el 70% del tiempo.