Errore di accumulo
-
02-10-2019 - |
Domanda
Ho una domanda abbastanza semplice. Il seguente codice stampa Celsius e Fahrenheit. La mia domanda riguarda tuttavia il numero di volte in cui iterazione. Per un piccolo numero ad esempio avvio 0, fermati a 10, con un passaggio di 1.1. Dopo che il ciclo è terminato, stamperà il numero corretto di iterazioni realizzate.
Ma per un numero elevato 0-11000000, con il passaggio 1.1 stamperà il numero sbagliato di iterazione. Perché sta succedendo? Poiché il 1100000/1.1 dovrebbe essere circa 1000001, ma ottengo 990293.
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
float start, stop, step;
int count = 0;
cout << "start temperature: ";
cin >> start;
cout << "stop temperature: ";
cin >> stop;
cout << "step temperature: ";
cin >> step;
cout << setw(10) << "celsius" << setw(15) << "fahrenheit" << endl;
cout << setw(25) << "celsius" << setw(15) << "fahrenheit" << endl;
while(start <= stop)
{
count++;
float c, f;
c = (5.0/9)*(start-32);
f = 32+(9.0/5)*start;
cout << setw(10) << fixed << setprecision(2) << c << setw(15) << start << setw(15) << fixed << setprecision(2) << f << " count: " << count << endl;
start = start + step;
}
cout << "The program loop made " << count << " iterations." << endl;
return 0;
}
Soluzione
Errore di arrotondamento a punta mobile. In sostanza, i galleggianti non sono una rappresentazione accurata al 100%, ci sono errori in ogni calcolo che fai e, come aggiungi ripetutamente ad essi, aggiungerai sempre più errori. Quello che dovresti fare è calcolare il numero di passaggi una volta, memorizzarlo in un numero intero e quindi in loop che molte volte.
Altri suggerimenti
Per il record, una versione pulita sarebbe:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double start, stop, step;
cout << "start temperature: ";
cin >> start;
cout << "stop temperature: ";
cin >> stop;
cout << "step temperature: ";
cin >> step;
cout << setw(10) << "celsius" << setw(15) << "fahrenheit" << endl;
unsigned steps = (stop - start) / step;
for(unsigned i = 0; i < steps; ++i)
{
double temp = start + i * step;
double c = (5.0 / 9.0) * (temp - 32.0);
double f = 32.0 + (9.0 / 5.0) * temp;
// This is a real good example of why people hate <iostream> formatting.
// If you want formatting that's quite different from the default, it
// gets too verbose too fast. Using C stdio:
//printf("%10.2f%15.2f\n", c, f);
cout << setw(10) << fixed << setprecision(2) << c
<< setw(15) << fixed << setprecision(2) << f << endl;
}
cout << "The program loop made " << steps << " iterations." << endl;
return 0;
}
Il principale vantaggio di questo stile di loop è che ogni iterazione è (ad eccezione dell'output) indipendente dall'ordine, quindi potrebbe essere srotolato e (teoricamente) parallelizzato.