2012-12-17 2 views
19

Addition tiene matematicamente la proprietà associativa:Le operazioni in virgola mobile sono associate in C?

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

Nel caso generale, questa struttura non vale per i numeri a virgola mobile perché rappresentano valori in precisione finita.

Un compilatore è autorizzato a eseguire la sostituzione di cui sopra durante la generazione di codice macchina da un programma C come parte di un'ottimizzazione? Dove dice esattamente nello standard C?

+1

Per la moltiplicazione almeno, guarda qui: http://stackoverflow.com/questions/6430448/why-doesnt-gcc-optimize-aaaaaa-to-aaaaaa –

risposta

12

Il compilatore non è autorizzato a eseguire "ottimizzazioni", che comporterebbero un valore diverso calcolato rispetto a quello calcolato in base alla semantica macchina astratta.

5.1.2.3 L'esecuzione del programma

[# 1] Le descrizioni semantiche di questo norma internazionale descrivono il comportamento di una macchina astratta in che le questioni di ottimizzazione sono irrilevanti.

[# 3] Nella macchina astratta, tutte le espressioni vengono valutate come specificato dalla semantica.

[# 13] ESEMPIO 5 Riarrangiamento per le espressioni a virgola mobile è spesso limitato a causa delle limitazioni di precisione come nonché intervallo. L'implementazione non può generalmente applicare le regole associative matematiche per l'addizione o la moltiplicazione , né la regola distributiva, a causa dell'errore roundoff , anche in assenza di overflow e underflow.

Nel tuo esempio:

(a + b) + c 

o anche senza le parentesi:

a + b + c 

abbiamo

+ 
/\ 
    + c 
/\ 
a b 

e il compilatore è necessario per generare il codice come se a è sommato con b e il risultato viene sommato con c.

+0

Teoria corretta. L'applicazione da portare a casa è: stabilisci in che ordine devono essere eseguite le tue operazioni (es. Se vuoi sommare da piccole a piccole, da grandi a grandi), mettere tra parentesi per soddisfare la paranoia, e puoi smettere di preoccuparti del fatto che il compilatore rompa le cose riordino. –

+0

Si noti tuttavia che mentre la precedenza degli operatori è ben definita, l'ordine di valutazione delle espressioni secondarie non è specificato. In altre parole, il programma può valutare questo albero binario che inizia da destra a sinistra, o da sinistra a destra, e non deve nemmeno mantenere questo ordine in modo coerente, né deve documentarlo. Quindi se a, b o c conteneva effetti collaterali che influivano sul risultato, allora il codice sarebbe problematico. Supponiamo ad esempio che c sia una funzione che modifica a: allora non potremmo sapere il risultato. – Lundin

5

La moltiplicazione in virgola mobile in C non è associativa.

In C, Floating point multiplication is not associative. 

Alcune prove è con questo codice C:

scegliere tre valori float casuali.
Verificare a*(b*c) è mai diverso da (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; 
} 

Il programma stampa:

Not equal 
Not equal 
Not equal 
Not equal 
DONE 
RUN FINISHED; exit value 0; real time: 10ms; user: 0ms; system: 0ms 

Conclusione:

Per la mia prova, tre valori moltiplicazione virgola mobile vengono casualmente associativo circa il 70% delle volte.

+0

L'OP ha chiesto se il compilatore * presuppone che le operazioni float siano associative, quando esegue ottimizzazioni. È chiaramente consapevole che in realtà non lo sono. –

+0

Sì, ma è sempre bello vedere un esempio che conferma la teoria. –