2011-09-10 12 views
5

ho scritto il seguente codice C++:uscita imprevisto durante l'aggiunta di due numeri float

float a, b; 
int c; 

a = 8.6; 
b = 1.4; 
c = a + b; 

printf("%d\n", c); 

L'uscita è 10.

Ma quando ho eseguito il seguente codice:

float a, b; 
int c; 

a = 8.7; 
b = 1.3; 
c = a + b; 

printf("%d\n", c); 

L'uscita è 9.

Qual è la differenza tra i due, in quanto forniscono output diversi?

risposta

15

Non esiste un numero come 8.7 o 1.3 in virgola mobile. C'è un numero 10 e un numero -6.5 e un numero 0.96044921875 ... ma non 8.7 o 1.3.

Nella migliore delle ipotesi, il computer può arrotondare 8,7 al numero a virgola mobile più vicino e arrotondare a 1,3 al numero a virgola mobile più vicino. Il computer aggiunge questi numeri arrotondati l'uno all'altro, quindi arrotonda il risultato.

Non utilizzare i numeri in virgola mobile per denaro.

#include <stdio.h> 
int main(int argc, char *argv[]) 
{ 
    float a = 8.7, b = 1.3; 
    printf("Looks like: %.1f + %.1f = %.1f\n", a, b, a+b); 
    printf("The truth: %.20f + %.20f = %.20f\n", a, b, a+b); 
    return 0; 
} 

Su un GCC x86/computer Linux, ottengo il risultato:

 
Looks like: 8.7 + 1.3 = 10.0 
The truth: 8.69999980926513671875 + 1.29999995231628417969 = 9.99999976158142089844 

Su un computer PPC GCC/OS X, ottengo il risultato:

 
Looks like: 8.7 + 1.3 = 10.0 
The truth: 8.69999980926513671875 + 1.29999995231628417969 = 10.00000000000000000000 

Avviso come 8.7 e 1.3 sono entrambi arrotondati in questo caso particolare. Se hai scelto i numeri che vengono arrotondati, potresti vedere un numero maggiore di 10 sul lato destro.

Vedi Ciò che ogni computer Scientist dovrebbe sapere aritmetica alla virgola mobile, da David Goldberg (link).

+2

Non utilizzare ** binary ** floating-point per denaro. Il virgola mobile decimale è stato standardizzato precisamente per le applicazioni finanziarie. –

+0

@Pascal Cuoq: Non si dovrebbe usare un decimale a punti fissi per soldi? In alcuni casi tale aritmetica è legalmente obbligatoria ... –

2

I numeri in virgola mobile non corrispondono ai numeri reali e il loro comportamento è molto diverso.

I numeri reali sono infiniti, mentre i numeri in virgola mobile sono finiti e possono rappresentare solo un piccolo sottoinsieme di tutti i possibili numeri reali.

Poiché non tutti i numeri reali possono essere rappresentati come virgola mobile, un'assegnazione o un'operazione in virgola mobile può fornire risultati leggermente diversi rispetto a quelli eseguiti nello spazio dei numeri reali.

Vedere wikipedia entry on floating point per un'introduzione. La sezione su floating point accuracy è particolarmente interessante e fornisce altri esempi simili ai tuoi.

0

Non c'è alcuna differenza tra i due. Entrambi si comportano in modi imprevedibili.

Quello che stai facendo equivale a lanciare una moneta due volte e chiedendo cosa hai fatto in modo diverso per ottenere una volta la testa e l'altra croce. Non è che hai fatto qualcosa di diverso, è che questo è quello che succede quando si lanciano le monete.

Se si chiede a una persona di aggiungere un terzo e due terzi utilizzando la precisione decimale a 6 cifre e quindi arrotondare a un numero intero, è possibile ottenere 0 e si potrebbe ottenere 1. Dipenderà da cose come se rappresentino 2/3 come "0.666666" o "0.6666667" e sono entrambi accettabili. Quindi sia 0 che 1 sono risposte accettabili. Se non sei pronto ad accettare nessuna risposta, non chiedere questo tipo di domanda.

+2

In virgola mobile, 0,666667 è l'unica rappresentazione accettabile di 2/3 con 6 cifre decimali. Alcune operazioni (+, -, *, /, sqrt) devono essere entro 1/2 ULPS della risposta esatta, e 0.666666 non soddisfa questo criterio per calcolare il valore di 2/3. –

+0

Non stavo parlando di virgola mobile, stavo parlando di precisione decimale a 6 cifre, che è un tipo di punto fisso. (Era un'analogia). –

+0

Stavo anche parlando del decimale a 6 cifre. 1/2 ULP significa che il risultato del calcolo del 2/3 deve essere compreso tra 1/2 x 10^-6 di 2/3, che è soddisfatto dai soliti metodi di arrotondamento insegnati a scuola. Gli unici casi in cui non si è sicuri del risultato sono quelli con un 5 nell'ultimo posto, ad esempio 0,5 può arrotondare a 0 o 1 a seconda della scelta delle regole (arrotondare, arrotondare, arrotondare a zero, arrotondare da zero, rotondo verso anche). Tuttavia, non esiste un insieme di regole accettabili che facciano passare il 2/3 a 0,666666. –

Problemi correlati