Leggi dal calcolo della varianza dei file

@Jerry Coffin

Ottengo la logica, mentre (File >> valore) // mentre l’input appena estratto dal file è vero …. fare computazione. Tuttavia, quando ho implementato questo, il contatore è andato a 1 e il suo valore era molto alto. A volte è sbagliato, ma non ho idea di cosa. Il file è valido

File.open(FileName, ifstream::in); while(File>>value){ ++counter; sum += value; sumsqr+= value * value; } average=sum/counter; variance = sumsqr/counter - average*average; File.close(); 

Ecco il contenuto del file di input Sto usando “text.txt” 23244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 1486415241250586205864104818638684840823244564 14864152412505862058641048186386848408

Tristemente, (almeno) tre risposte hanno citato il tuo while (!File.eof()) senza commentare il fatto che questo è semplicemente sbagliato. Quello che vuoi è qualcosa del genere:

 while (File>>value) { ++counter; sum += value; sumsqr += value * value; } average = sum/counter; variance = sumsqr/counter - average * average; 

Il bug da usare while (!File.eof()) è insidioso: di solito ottieni risultati che sembrano ragionevoli e in realtà sono abbastanza vicini alla correttezza. Il problema è che eof() non diventa vero fino a quando non si è tentato di leggere dal file e la lettura tentata non è riuscita. Quando fallisce, il value avrà ancora l’ultimo valore letto, quindi si comporterà come se l’ultimo numero nell’elenco fosse realmente presente due volte (ad esempio, se il tuo file contenesse 21 numeri, il tuo ciclo sarebbe stato eseguito 22 volte e sul 22 a iterazione, userebbe di nuovo il 21 ° numero). In questo modo i calcoli spariranno un po ‘, ma di solito non è sufficiente che sia immediatamente ovvio – quasi il peggior tipo di bug ansible.

Modifica: ecco un programma di test completo:

 #include  #include  double variance(std::istream &File) { double value, average, sum, counter, sumsqr, variance; while (File>>value) { ++counter; sum += value; sumsqr += value * value; } average = sum/counter; variance = sumsqr/counter - average * average; return variance; } double variance2(std::istream &File) { double value, average, sum, counter, sumsqr, variance; while (!File.eof()) { ++counter; File >> value; sum += value; sumsqr += value * value; } average = sum/counter; variance = sumsqr/counter - average * average; return variance; } int main() { std::ifstream in("data.txt"); double v1 = variance1(in); in.clear(); in.seekg(0); double v2 = variance2(in); std::cout << "Using \"while (file>>value)\"" << v1 << "\n"; std::cout << "Using \"while (!file.eof())\"" << v2 << "\n"; return 0; } 

Ecco alcuni dati di test con cui andare:

 1 2 3 4 5 6 7 8 9 10 

Quando eseguo questo su quei dati, ottengo:

 Using "while (file>>value)": 8.25 Using "while (!file.eof())": 9.17355 

Come controllo incrociato, ho eseguito il calcolo in Excel, utilizzando due serie di dati:

 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 8.25 10 9.173553719 

L'ultima riga in ogni colonna è il risultato di una formula che esegue "VARP" sui dati precedenti. Si noti che la mia funzione corrisponde a ciò che Excel produce per i dati di input corretti. La funzione che utilizza while (!file.eof()) corrisponde a ciò che Excel produce con l'ultimo numero duplicato.

Non riesco nemmeno a indovinare cosa sta succedendo per far funzionare il ciclo una sola volta e leggere un valore errato. Senza essere in grado di indovinare o riprodurre il problema, temo di non poter fornire molti suggerimenti utili su come risolverlo.

Il tuo calcolo della varianza è totalmente errato. In termini statistici, la varianza è

 E(x^2) - [E(x)^2] 

Quindi sbarazzati di quel secondo ciclo (non sono nemmeno sicuro di quello che pensi che faccia) e cambia il primo ciclo per:

 while(!File.eof()){ counter++; value = File.get(); sum += value; sumsqr += value*value; } average = sum/counter; variance = (sumsqr/counter) - (average*average); 

EDIT: la risposta di Jerry Coffin è ancora migliore in quanto dimostra il problema con eof() .

puoi scrivere così

 variance=counter*(average*average) 

Nel secondo ciclo !File.eof() , non stai leggendo dal file. La varianza non è la sum dei quadrati delle differenze tra i valori e la media? Il tuo ciclo non guarda affatto i valori dal file. Inoltre, l’utilizzo di variabili intere per la sum, la media e la varianza può portare a imprecisioni; potresti volere il double per quelli invece.

 while(!File.eof()){ variance +=(average*average); } 

Le linee precedenti non sembrano avere molto senso. Non stai leggendo nulla in quel mentre blocchi. Questo mentre il blocco non dovrebbe terminare.

Bene, se la domanda non limita le librerie che è ansible utilizzare, suggerirei di utilizzare gli Accumulatori Boost che rendono banale questo tipo di cosa.

Ottieni varianza, media e qualsiasi altro valore statistico di base che desideri. Hanno alcuni problemi con il long double , ma per il resto sono fantastici!