View Full Version : [C++] Caricare dati float da txt
Mattiatn
10-09-2008, 10:43
Ciao a tutti, chissà quante volte vi è stata fatta questa domanda, cercando in giro ho trovato più proposte con le quali però nascono ulteriori problemi che non sò risolvere.
il file txt dal quale devo leggere è composto da una serie di colonne con numeri in forma esponenziale (es: 1.03948e+12), vorrei leggere il file txt e disporre dei dati sottoforma di array.
Essendo totalmente inetto in c++ :mc: se non in qualche passaggio semplice, vi sarei estremamente grato se mi potrete aiutare. Grazie mille.
Vincenzo1968
10-09-2008, 18:32
Ciao a tutti, chissà quante volte vi è stata fatta questa domanda, cercando in giro ho trovato più proposte con le quali però nascono ulteriori problemi che non sò risolvere.
il file txt dal quale devo leggere è composto da una serie di colonne con numeri in forma esponenziale (es: 1.03948e+12), vorrei leggere il file txt e disporre dei dati sottoforma di array.
Essendo totalmente inetto in c++ :mc: se non in qualche passaggio semplice, vi sarei estremamente grato se mi potrete aiutare. Grazie mille.
Ciao Mattia,
ti chiedo qualche informazione sul formato del file:
- I numeri come sono separati? Virgola, spazio, punto e virgola?
- La prima riga contiene contiene informazioni sulla dimensione della matrice(numero di righe e colonne) o parte subito dai dati?
Mattiatn
11-09-2008, 09:46
si, i numeri sono separati, sono del tipo in allegato, il numero di colonne dovrebbe essere di 365 (lettura di un laser a scansione) con separazione per mezzo di spazi, e non vi sono informazioni sulle dimensioni, che però rimane costante.
Grazie per l'interessamento
Vincenzo1968
12-09-2008, 02:00
Il programma seguente implementa un automa a stati finiti che legge il file di testo e restituisce il risultato in una struttura che contiene, come campi, l'array, il numero di righe e il numero di colonne.
Con questo file:
2.025e+12 3.125e-15 2.125e-5
1.0125e-10 2.031e+10 5.12548e-12
l'output è:
array[0][0] -> 2.025e+012
array[1][2] -> 5.12548e-012
#include <iostream>
using namespace std;
#define BUFFER_SIZE 4096
typedef struct tagArray
{
size_t rows;
size_t cols;
double **m;
} Array;
typedef enum tagStati
{
S_ERROR = -1, S0 = 0, S1, S2, S3, S4, S5, S6, S7, S8, S9
} Stati;
Stati DFA(const char *szFileName, Array *pArray)
{
Stati stato = S0;
FILE *fp;
unsigned char buffer[BUFFER_SIZE];
int numblocks;
int numread;
unsigned char c;
int k, x, j;
int riga, colonna;
char szNum[256];
double num;
bool bCountCols = true;
unsigned char byteCR = 0xD; // Carriage Return
unsigned char byteLF = 0xA; // Line Feed
pArray->rows = 0;
pArray->cols = 0;
fp = fopen(szFileName, "rb"); // Warning C4996 -> Usare fopen_s
if ( fp == NULL )
{
cout << "Errore nell'apertura del file " << szFileName << endl;
return S_ERROR;
}
if ( fseek(fp, 0, SEEK_END) )
return S_ERROR;
numblocks = ftell(fp)/BUFFER_SIZE;
if ( numblocks == 0 )
{
numblocks = 1;
}
else
{
if ( ftell(fp) % BUFFER_SIZE != 0 )
numblocks++;
}
fseek(fp, 0, SEEK_SET);
while ( 1 )
{
k = 0;
numread = fread(buffer, 1, BUFFER_SIZE, fp);
if ( numread == 0 )
break;
for ( k = 0; k < numread; k++ )
{
if ( *(buffer + k) == byteLF )
{
pArray->rows++;
bCountCols = false;
}
else if ( bCountCols && *(buffer + k) != ' ' )
{
pArray->cols++;
while ( *(buffer + k) != ' ' )
{
k++;
if ( k == numread )
break;
if ( *(buffer + k) == byteLF )
{
pArray->rows++;
bCountCols = false;
break;
}
}
}
}
if ( numread < BUFFER_SIZE )
break;
}
if ( fseek(fp, -1, SEEK_END) )
return S_ERROR;
fread(buffer, 1, 1, fp);
if ( *buffer != byteLF )
pArray->rows++;
pArray->m = new double*[pArray->rows];
if ( pArray->m )
{
for ( size_t row(0); row != pArray->rows; ++row )
{
pArray->m[row] = new double[pArray->cols];
if ( !pArray->m[row] )
{
cout << "Memoria insufficiente." << endl;
fclose(fp);
return S_ERROR;
}
}
}
else
{
cout << "Memoria insufficiente." << endl;
fclose(fp);
return S_ERROR;
}
fseek(fp, 0, SEEK_SET);
numread = fread(buffer, 1, BUFFER_SIZE, fp);
riga = colonna = 0;
num = 0;
x = k = j = 0;
while ( x < numblocks )
{
c = *(buffer + k++);
if ( c == byteCR )
{
if ( k >= numread )
{
numread = fread(buffer, 1, BUFFER_SIZE, fp);
k = 0;
x++;
}
c = *(buffer + k++);
}
switch (stato)
{
case S0:
j = 0;
if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S1;
}
else if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S2;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S3;
}
else
{
cout << "Errore: stato S0 << riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S1:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S2;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S3;
}
else
{
cout << "Errore: stato S1 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S2:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S4;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S5;
}
else if ( c == ' ' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S2 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S3:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else
{
cout << "Errore: stato S3 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S4:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S7;
}
else if ( c == ' ' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S4 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S5:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S8;
}
else
{
cout << "Errore: stato S5 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S6:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S7;
}
else if ( c == ' ' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S6 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S7:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S8;
}
else
{
cout << "Errore: stato S7 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S8:
case S9:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == ' ' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S9 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
}
if ( k >= numread )
{
numread = fread(buffer, 1, BUFFER_SIZE, fp);
k = 0;
x++;
}
}
fclose(fp);
if ( stato == S2 || stato == S4 || stato == S6 || stato == S9 )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
}
return stato;
}
int main()
{
Stati stato;
Array myArray;
char *szFileName = "prova.txt";
stato = DFA(szFileName, &myArray);
if ( stato == S0 || stato == S2 || stato == S4 || stato == S6 || stato == S9 )
{
// stampa il primo elemento dell'array(riga 0, colonna 0)
cout << endl << "array[0][0] -> " << myArray.m[0][0] << endl;
// stampa l'ultimo elemento(ultima riga, ultima colonna)
cout << "array[" << myArray.rows - 1 << "][" << myArray.cols - 1 << "] -> " << myArray.m[myArray.rows - 1][myArray.cols - 1] << endl;
for ( size_t row(0); row != myArray.rows; ++row )
delete [] myArray.m[row];
delete [] myArray.m;
}
else
{
cout << "L'automa ha restituito un errore. Stato " << stato << endl;
}
return 0;
}
Mattiatn
12-09-2008, 07:57
Grazie mille, adesso lo provo.
Spero che non sei stato sveglio fino alle 2 per me!:eek:
Il programma seguente implementa un automa a stati finiti che legge il file di testo e restituisce il risultato in una struttura che contiene, come campi, l'array, il numero di righe e il numero di colonne.
Con questo file:
2.025e+12 3.125e-15 2.125e-5
1.0125e-10 2.031e+10 5.12548e-12
l'output è:
array[0][0] -> 2.025e+012
array[1][2] -> 5.12548e-012
[cut per pietà] ammazza che porcata, hai reinventato circa una dozzina di ruote implementando in C++ una macchina a stati e perdipiù facendo uso della libreria di I/O del C :asd:
e occhio, ci sta pure il commento (C++ - like) che ti avvisa che a quella linea il compilatore ti da' il warning C4996 :sofico: :rotfl:
ti offendi se ti dico che si risolveva tutto con molto meno? :rolleyes:
#include <iostream>
#include <fstream>
#include <list>
using namespace std;
struct Vector
{
float x;
float y;
float z;
};
istream &operator >> (istream &source, Vector &v)
{
return source >> v.x >> v.y >> v.z;
}
ostream &operator << (ostream &sink, const Vector &v)
{
return sink << v.x << ", " << v.y << ", " << v.z << endl;
}
int main()
{
ifstream source("input.txt", ifstream::in);
if (!source.good())
{
return 1;
}
list<Vector> vectors;
while (!source.eof())
{
Vector v;
source >> v;
vectors.push_back(v);
}
for (list<Vector>::iterator i = vectors.begin(); i != vectors.end(); i++)
{
cout << *i;
}
return 0;
}
:fagiano:
Vincenzo1968
12-09-2008, 22:09
ammazza che porcata, hai reinventato circa una dozzina di ruote implementando in C++ una macchina a stati e perdipiù facendo uso della libreria di I/O del C :asd:
e occhio, ci sta pure il commento (C++ - like) che ti avvisa che a quella linea il compilatore ti da' il warning C4996 :sofico: :rotfl:
ti offendi se ti dico che si risolveva tutto con molto meno? :rolleyes:
...
:fagiano:
Porcata? Dipende.
La tua implementazione è una porcata dal punto di vista delle prestazioni.
Vogliamo provare a confrontare i tempi su file di grosse dimensioni? :)
Vincenzo1968
12-09-2008, 22:33
Se modifico il file di esempio da cosi:
2.025e+12 3.125e-15 2.125e-5
1.0125e-10 2.031e+10 5.12548e-12
a cosi:
2.025e+12 3.125e-15 2.125e-5
1.0125e-10 2.ciao 5.12548e-12
La mia implementazione restituisce il seguente messaggio di errore:
Errore stato S4 riga 1 colonna 1
La tua breve(nonché intelligente) applicazione, si blocca :)
Vincenzo1968
13-09-2008, 00:38
Ho preso i tempi di esecuzione:
http://www.guidealgoritmi.it/images/ImgForums/confronto.jpg
La tua versione, pur non eseguendo nessun lavoro di gestione degli errori, è più lenta della mia.
I file di test li ho creati con questo codice:
void CreaDoubleFile()
{
FILE *fp;
int i, j;
int n1, n2;
char szNum[256];
fp = fopen("test.txt", "w+");
srand((unsigned)time(NULL));
for ( i = 0; i < 100000; i++ )
{
for ( j = 0; j < 365; j++ )
{
n1 = rand();
n2 = rand();
itoa(n1, szNum, 10);
strcat(szNum, ".1e-5");
fwrite(szNum, strlen(szNum), 1, fp);
if ( j < 364 )
fwrite(" ", 1, 1, fp);
}
fwrite("\n", 1, 1, fp);
//printf("record n. %d\n", i);
}
fclose(fp);
}
Il primo è un file che contiene 1.000 righe e 365 colonne di numeri double nel formato scientifico. 0.82 secondi contro 0.28 secondi.
Il secondo contiene 100.000 righe e 365 colonne. 83 secondi contro 35.
Preferisco reinventare l'acqua calda e avere codice efficiente, e dal punto di vista delle prestazioni, e da quello delle funzionalità(gestione degli errori), piuttosto che scrivere due righe di codice per avere programmi... come definirli? Porcate? :)
slartibartfast
13-09-2008, 01:19
Ho preso i tempi di esecuzione:
http://www.guidealgoritmi.it/images/ImgForums/confronto.jpg
cut
Ti si legge “” dal path... :fiufiu: :asd:
Vincenzo1968
13-09-2008, 01:28
Ti si legge “coglione” dal path... :fiufiu: :asd:
oops non me n'ero accorto.
Grazie per la segnalazione, provvedo subito :D
Vincenzo1968
13-09-2008, 03:27
E per fortuna c'è anche chi la pensa diversamente sulle 'porcate' che scrivo:
http://www.democritos.it:8888/O-sesame/chngview?cn=6026
:)
Vincenzo1968: tolgo le due mail, il mittente, che specifico non è alcun utente del forum, non ti ha certo autorizzato a pubblicare i suoi dati personali.
Inoltre Vincenzo1968 ti prendi una sospensione di 3 gg per il "coglione" nel path.
71104: continui a rivolgerti agli altri utenti come se fossero tuoi compagni di merende, non lo sono, ricordati che comportamenti di questo tipo non saranno oltremodo tollerati in tutto il forum. 1 giorno di sospensione
Tornando alla questione iniziale, il linguaggio richiesto era il C++ e non il C e le prestazioni non sono tutto, anzi, nel 90% dei casi non sono niente.
Mattiatn
13-09-2008, 09:38
Pensavo anche io inizialmente che un programma così non lungo (data la mia inesperienza) fosse estremamente lento, ma invece è molto veloce, e questo è ben accetto sopratutto in previsioni di applicazioni real-time.
Se mi permetti invece, volevo domandarti dove era possibile eliminare dal programma la segnalazione di errore relativo a come sono separati i dati, poichè mi sono accorto che il file di txt molto spesso separa con caratteri diversi dal solo spazio (doppio spazio, carattere di rientro(quello vicino a q sulla tastiera, non mi ricordo il nome)). Grazie ancora!!:D
In C++ lo farei così:
struct Data
{
float x;
float y;
float z;
};
int parseLine(string line, Data &d)
{
istringstream iss(line);
iss >> d.x >> d.y >> d.z;
return iss.fail();
}
int main()
{
ifstream inputFile("nomefile");
while(1)
{
string line;
getline(inputFile, line);
if(inputFile.fail())
break;
vector<Data> v;
Data d;
if(parseLine(line, d))
{
cout << "Malformed line" << endl;
break;
}
v.push_back(d);
}
return 0;
}
Poi per le prestazioni: si possono sempre aumentare se ce n'è bisogno.
Per i tab e i doppi spazi non ti devi preoccupare, almeno nel mio caso li salta tutti.
Vincenzo1968
16-09-2008, 09:26
In C++ lo farei così:
...
Poi per le prestazioni: si possono sempre aumentare se ce n'è bisogno.
Per i tab e i doppi spazi non ti devi preoccupare, almeno nel mio caso li salta tutti.
Ohé Cionci,
vero è che li salta tutti, i tab e gli spazi, ma salta anche, per ogni riga, le restanti 362 colonne ;)
Mattia ha specificato che le colonne dovrebbero essere 365 ;)
Il mio automa, le colonne le calcola al volo(basandosi sulla prima riga) e crea un array bidimensionale adeguato.
Col vostro programma che bisogna fare? Utilizzare una struttura con 365 campi?
E se debbo leggere in sequenza più file, ognuno dei quali con un numero di colonne diverso?
Mi permetto di suggerire l'uso di un vettore di vettori dimensionato in modo dinamico. Ecco un esempio:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <time.h>
using namespace std;
template <typename T>
class MyArray
{
public:
MyArray()
{
m_righe = 0;
m_colonne = 0;
}
MyArray(int righe, int colonne) : myArray(righe, vector<T>(colonne))
{
m_righe = righe;
m_colonne = colonne;
}
vector<T> & operator[](int i)
{
return myArray[i];
}
const vector<T> & operator[] (int i) const
{
return myArray[i];
}
void resize(int righe, int colonne)
{
myArray.resize(righe);
for( int i = 0; i < righe; ++i )
myArray[i].resize(colonne);
}
private:
vector<vector<T>> myArray;
int m_righe;
int m_colonne;
};
int parseLine(string line, MyArray<double> &d, int riga, int numcols)
{
istringstream iss(line);
for ( int i = 0; i < numcols; i++ )
iss >> d[riga][i];
return iss.fail();
}
void GetSizes(const char *szFileName, int &righe, int &colonne)
{
string line;
ifstream inputFile(szFileName);
righe = colonne = 0;
getline(inputFile, line);
if(inputFile.fail())
return;
int k = 0;
while ( line[k] != '\0' )
{
if ( line[k] == ' ' || line[k] == '\t' )
colonne++;
k++;
}
righe = 1;
while(1)
{
getline(inputFile, line);
if(inputFile.fail())
break;
righe++;
}
if ( colonne > 0 )
colonne++;
}
int main()
{
int righe, colonne;
char *szFileName = "C:\\Temp\\test3.txt";
clock_t c_start, c_end;
c_start = clock();
GetSizes(szFileName, righe, colonne);
MyArray<double> v(righe, colonne);
ifstream inputFile(szFileName);
int riga = 0;
while(1)
{
string line;
getline(inputFile, line);
if(inputFile.fail())
break;
if( parseLine(line, v, riga, colonne) )
{
cout << "Malformed line" << endl;
break;
}
riga++;
}
c_end = clock();
cout << endl;
cout << "v[0][0] -> " << v[0][0] << endl;
cout << "v[" << righe - 1 << "][" << colonne - 1 << "] -> " << v[righe - 1][colonne - 1] << endl;
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
È abbastanza C++-Like e Object-Oriented?
Questo è il risultato sul file di 100.000 righe e 365 colonne:
http://www.guidealgoritmi.it/images/ImgForums/confrontoCPP.jpg
Il codice che ho scritto(il primo, quello con l'automa) è in C++. Utilizzo le funzioni del C per la gestione dei file, solo perchè queste sono più efficienti degli fstream del C++.
Ti posso citare una mezza dozzina di libri al riguardo o, se preferisci, posso postare il risultato di vari test che ho effettuato sulla mia macchina.
Infine, non ti sembra troppo generica la tua gestione degli errori? L'automa riporta la riga e la colonna dove l'errore s'è verificato.
Il tuo programma se ne esce con un messaggio generico. Pensa se un compilatore, quando trova un errore, riporta il seguente messaggio all'utente:
C'è un errore nel codice
senza indicare il file e la presunta riga ;)
Posto il codice modificato in modo da tenere conto sia degli spazi multipli che dei caratteri di tabulazione:
#include <iostream>
#include <time.h>
using namespace std;
#define BUFFER_SIZE 4096
typedef struct tagArray
{
size_t rows;
size_t cols;
double **m;
} Array;
typedef enum tagStati
{
S_ERROR = -1, S0 = 0, S1, S2, S3, S4, S5, S6, S7, S8, S9
} Stati;
Stati DFA(const char *szFileName, Array *pArray)
{
Stati stato = S0;
FILE *fp;
unsigned char buffer[BUFFER_SIZE];
int numblocks;
int numread;
unsigned char c;
int k, x, j;
int riga, colonna;
char szNum[256];
double num;
bool bCountCols = true;
unsigned char byteCR = 0xD; // Carriage Return
unsigned char byteLF = 0xA; // Line Feed
pArray->rows = 0;
pArray->cols = 0;
fp = fopen(szFileName, "rb"); // Warning C4996 -> Usare fopen_s
if ( fp == NULL )
{
cout << "Errore nell'apertura del file " << szFileName << endl;
return S_ERROR;
}
if ( fseek(fp, 0, SEEK_END) )
return S_ERROR;
numblocks = ftell(fp)/BUFFER_SIZE;
if ( numblocks == 0 )
{
numblocks = 1;
}
else
{
if ( ftell(fp) % BUFFER_SIZE != 0 )
numblocks++;
}
fseek(fp, 0, SEEK_SET);
while ( 1 )
{
k = 0;
numread = fread(buffer, 1, BUFFER_SIZE, fp);
if ( numread == 0 )
break;
for ( k = 0; k < numread; k++ )
{
if ( *(buffer + k) == byteLF )
{
pArray->rows++;
bCountCols = false;
}
else if ( bCountCols && *(buffer + k) != ' ' )
{
pArray->cols++;
while ( *(buffer + k) != ' ' )
{
k++;
if ( k == numread )
break;
if ( *(buffer + k) == byteLF )
{
pArray->rows++;
bCountCols = false;
break;
}
}
}
}
if ( numread < BUFFER_SIZE )
break;
}
if ( fseek(fp, -1, SEEK_END) )
return S_ERROR;
fread(buffer, 1, 1, fp);
if ( *buffer != byteLF )
pArray->rows++;
pArray->m = new double*[pArray->rows];
if ( pArray->m )
{
for ( size_t row(0); row != pArray->rows; ++row )
{
pArray->m[row] = new double[pArray->cols];
if ( !pArray->m[row] )
{
cout << "Memoria insufficiente." << endl;
fclose(fp);
return S_ERROR;
}
}
}
else
{
cout << "Memoria insufficiente." << endl;
fclose(fp);
return S_ERROR;
}
fseek(fp, 0, SEEK_SET);
numread = fread(buffer, 1, BUFFER_SIZE, fp);
riga = colonna = 0;
num = 0;
x = k = j = 0;
while ( x < numblocks )
{
c = *(buffer + k++);
if ( c == byteCR )
{
if ( k >= numread )
{
numread = fread(buffer, 1, BUFFER_SIZE, fp);
k = 0;
x++;
}
c = *(buffer + k++);
}
switch (stato)
{
case S0:
j = 0;
if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S1;
}
else if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S2;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S3;
}
else if ( c == ' ' || c == '\t' )
{
while ( c == ' ' || c == '\t' )
{
c = *(buffer + k++);
if ( k >= numread )
break;
}
k--;
}
else
{
cout << "Errore: stato S0 << riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S1:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S2;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S3;
}
else
{
cout << "Errore: stato S1 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S2:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S4;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S5;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S2 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S3:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else
{
cout << "Errore: stato S3 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S4:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S7;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S4 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S5:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S8;
}
else
{
cout << "Errore: stato S5 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S6:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S7;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S6 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S7:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S8;
}
else
{
cout << "Errore: stato S7 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S8:
case S9:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S9 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
}
if ( k >= numread )
{
numread = fread(buffer, 1, BUFFER_SIZE, fp);
k = 0;
x++;
}
}
fclose(fp);
if ( stato == S2 || stato == S4 || stato == S6 || stato == S9 )
{
szNum[j] = '\0';
pArray->m[riga][colonna] = atof(szNum);
}
return stato;
}
int main()
{
Stati stato;
Array myArray;
clock_t c_start, c_end;
char *szFileName = "C:\\Temp\\test3.txt";
c_start = clock();
stato = DFA(szFileName, &myArray);
c_end = clock();
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
if ( stato == S0 || stato == S2 || stato == S4 || stato == S6 || stato == S9 )
{
// stampa il primo elemento dell'array(riga 0, colonna 0)
cout << endl << "array[0][0] -> " << myArray.m[0][0] << endl;
// stampa l'ultimo elemento(ultima riga, ultima colonna)
cout << "array[" << myArray.rows - 1 << "][" << myArray.cols - 1 << "] -> " << myArray.m[myArray.rows - 1][myArray.cols - 1] << endl;
for ( size_t row(0); row != myArray.rows; ++row )
delete [] myArray.m[row];
delete [] myArray.m;
}
else
{
cout << "L'automa ha restituito un errore. Stato " << stato << endl;
}
return 0;
}
Questo è il risultato:
http://www.guidealgoritmi.it/images/ImgForums/confronto2.jpg
Sfido chiunque a ottenere gli stessi tempi, in puro C++, con fstream e vector ;)
banryu79
16-09-2008, 09:46
E per fortuna c'è anche chi la pensa diversamente sulle 'porcate' che scrivo:
http://www.democritos.it:8888/O-sesame/chngview?cn=6026
:)
Vorrei leggere le info puntate da quel link ma non riesco a raggiungerlo, il browser mi va in timeout mentre tenta di caricare la pagina.
Il link è corretto?
Vincenzo1968
16-09-2008, 09:51
Ciao Banryu,
si, è corretto. Ho provato proprio adesso a cliccarci sopra e funziona :boh:
Ciao
P.S.
Approfitto per chiedere il permesso a Cionci di postare le due mail che ha tolto nel post precedente. Ho cancellato ogni riferimento all'autore delle mail, compreso il numero di telefono della società.
Riguardo alla gestione degli errori è stata volutamente lasciata così, basta un counter ed una lettura delle colonne separata per sapere riga e colonna dell'errore ;)
Che il numero di colonne sia variabile sinceramente non l'ho letto, credevo fossero tre :D Comunque mi sembra di aver letto che c'è il vincolo che le colonne sono massimo 365 e sono sempre in numero costante.
Le prestazioni al solito non sono tutto in un programma, molte volte è più importante la leggibilità e la manutenibilità ;)
Per aumentare le prestazioni siamo sempre in tempo ad andare a lavorare sul punto in cui le prestazioni sono deficitarie con un profiler, questo non è un grosso problema.
Per il numero di colonne variabili la questione è comunque abbastanza semplice:
class DataMatrix
{
vector<float *> matrix;
int currentColumn;
int columns;
int rows;
public:
DataMatrix(int columns)
{
this->columns = columns;
rows = 0;
newLine();
}
void insert(float f)
{
matrix.back()[currentColumn++] = f;
}
void newLine()
{
matrix.push_back(new matrix[columns]);
rows++;
}
int getLines() { return rows; };
int getRows() { return columns; };
float getElement(int row, int column)
{
return matrix[row][column];
}
~DataMatrix()
{
while(matrix.size() > 0)
{
delete[] matrix.back();
matrix.pop_back();
}
}
};
class MalformedLineException
{
int row;
int column;
string message;
public;
MalformedLineException(int row, int column)
{
this->row = row;
this->column = column;
ostringstream oss;
oss << "Malformed line at row " << row << " and column " << column;
message = oss.str();
}
string getMessage() { return message; };
int getRow() { return row; };
int getColumn() { return column; };
};
int countColumns(string line)
{
istringstream iss(line);
int lineCounter = 0;
while(1)
{
flot tmp;
iss >> tmp;
if(iss.fail() && !iss.eof())
throw MalformedLineException(1, lineCounter + 1);
if(iss.eof())
break;
lineCounter++;
}
return lineCounter;
}
void parseLine(string line, DataMatrix &data)
{
istringstream iss(line);
for(int i = 0; i < data.getColumns(); ++i)
{
float f;
iss >> f;
if(iss.fail())
throw MalformedLineException(data.getRows(), data.getColumns());
matrix.insert(f);
}
}
int main()
{
ifstream inputFile("nomefile");
try
{
string line;
getline(inputFile, line);
int columns = countColumns(line);
DataMatrix data(columns);
while(1)
{
if(inputFile.fail())
break;
data.newLine();
parseLine(line, data);
getline(inputFile, line);
}
}
catch(MalformedLineException ex)
{
cout << ex.getMessage();
}
return 0;
}
Ovviamente ci potrebbe essere qualche errore a giro perché l'ho scritto direttamente nella finestra del browser e non l'ho provato a compilare.
Per chiarirmi meglio sulle prestazioni...il problema è il vector ? Bene se castra le prestazioni si elimina e si aggiunge una riallocazione a blocchi.
Il problema è l'istringstream ? Si sostituisce con una lettura carattere per carattere fino al primo carattere che uno spazio (nel senso di isspace).
P.S.
Approfitto per chiedere il permesso a Cionci di postare le due mail che ha tolto nel post precedente. Ho cancellato ogni riferimento all'autore delle mail, compreso il numero di telefono della società.
Se vuoi, ma non vedo come possa contribuire alla discussione :boh:
Vincenzo1968
16-09-2008, 10:51
E per la richiesta che ho fatto nel post di risposta a Banryu? Posso ripostarle le e-mail?
Ciao
Vincenzo1968
16-09-2008, 10:53
Se vuoi, ma non vedo come possa contribuire alla discussione :boh:
In nessun modo, ma dato che il mio codice è stato definito 'pietoso' e 'porcata', ci tengo. Grazie :)
http://www.guidealgoritmi.it/images/ImgForums/mail1.jpg
http://www.guidealgoritmi.it/images/ImgForums/mail2.jpg
Vincenzo1968
16-09-2008, 11:48
Cionci,
non riesco a compilare il tuo codice:
error C2061: syntax error : identifier 'matrix'
Il codice è questo:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <time.h>
using namespace std;
class DataMatrix
{
vector<float *> matrix;
int currentColumn;
int columns;
int rows;
public:
DataMatrix(int columns)
{
this->columns = columns;
rows = 0;
newLine();
}
void insert(float f)
{
matrix.back()[currentColumn++] = f;
}
void newLine()
{
matrix.push_back(new matrix[columns]);
rows++;
}
int getRows() { return rows; };
int getColumns() { return columns; };
float getElement(int row, int column)
{
return matrix[row][column];
}
~DataMatrix()
{
while(matrix.size() > 0)
{
delete[] matrix.back();
matrix.pop_back();
}
}
};
class MalformedLineException
{
int row;
int column;
string message;
public:
MalformedLineException(int row, int column)
{
this->row = row;
this->column = column;
ostringstream oss;
oss << "Malformed line at row " << row << " and column " << column;
message = oss.str();
}
string getMessage() { return message; };
int getRow() { return row; };
int getColumn() { return column; };
};
int countColumns(string line)
{
istringstream iss(line);
int lineCounter = 0;
while(1)
{
float tmp;
iss >> tmp;
if(iss.fail() && !iss.eof())
throw MalformedLineException(1, lineCounter + 1);
if(iss.eof())
break;
lineCounter++;
}
return lineCounter;
}
void parseLine(string line, DataMatrix &data)
{
istringstream iss(line);
for(int i = 0; i < data.getColumns(); ++i)
{
float f;
iss >> f;
if(iss.fail())
throw MalformedLineException(data.getRows(), data.getColumns());
data.insert(f);
}
}
int main()
{
int rows;
clock_t c_start, c_end;
c_start = clock();
ifstream inputFile("C:\\Temp\\test3.txt");
try
{
string line;
getline(inputFile, line);
int columns = countColumns(line);
DataMatrix data(columns);
rows = 1;
while(1)
{
if(inputFile.fail())
break;
data.newLine();
parseLine(line, data);
getline(inputFile, line);
rows++;
}
cout << endl;
cout << "v[0][0] -> " << data.getElement(0, 0) << endl;
cout << "v[" << data.getRows() - 1 << "][" << data.getColumns() - 1 << "] -> " << data.getElement(rows - 1, columns - 1) << endl;
}
catch(MalformedLineException ex)
{
cout << ex.getMessage();
}
c_end = clock();
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
e la linea interessata, all'interno della funzione NewLine, è questa:
matrix.push_back(new matrix[columns]);
matrix.push_back(new float[columns]);
Sorry, ma l'ho scritto di getto senza compilarlo :D
Vincenzo1968
16-09-2008, 12:04
Adesso compila ma, eseguendolo, va in crash :cry:
Forse è qualche cavolata che ho combinato io modificando il codice.
Mi alleghi il file con i dati ?
Corretto:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <ctime>
using namespace std;
class DataMatrix
{
vector<float *> matrix;
int currentColumn;
int columns;
int rows;
public:
DataMatrix(int columns)
{
this->columns = columns;
rows = 0;
}
void insert(float f)
{
matrix.back()[currentColumn++] = f;
}
void newLine()
{
currentColumn = 0;
matrix.push_back(new float[columns]);
rows++;
}
int getRows()
{
return rows;
}
int getColumns()
{
return columns;
}
float getElement(int row, int column)
{
return matrix[row][column];
}
~DataMatrix()
{
while (matrix.size() > 0)
{
delete[] matrix.back();
matrix.pop_back();
}
}
};
class MalformedLineException
{
int row;
int column;
string message;
public:
MalformedLineException(int row, int column)
{
this->row = row;
this->column = column;
ostringstream oss;
oss << "Malformed line at row " << row << " and column " << column;
message = oss.str();
}
string getMessage()
{
return message;
}
int getRow()
{
return row;
}
int getColumn()
{
return column;
}
};
int countColumns(string line)
{
istringstream iss(line);
int columnCounter = 0;
while (1)
{
float tmp;
iss >> tmp;
if (iss.fail() && !iss.eof())
throw MalformedLineException(1, columnCounter + 1);
columnCounter++;
if (iss.eof())
break;
}
return lineCounter;
}
void parseLine(string line, DataMatrix &data)
{
istringstream iss(line);
for (int i = 0; i < data.getColumns(); ++i)
{
float f;
iss >> f;
if (iss.fail())
throw MalformedLineException(data.getRows(), i + 1);
data.insert(f);
}
}
int main()
{
clock_t c_start, c_end;
c_start = clock();
ifstream inputFile("data.txt");
if (inputFile.fail())
{
cout << "Error opening file" << endl;
return 1;
}
try
{
string line;
getline(inputFile, line);
int columns = countColumns(line);
DataMatrix data(columns);
while (!inputFile.fail())
{
data.newLine();
parseLine(line, data);
getline(inputFile, line);
}
cout << endl;
cout << "v[0][0] -> " << data.getElement(0, 0) << endl;
cout << "v[" << data.getRows() - 1 << "][" << data.getColumns() - 1 << "] -> " << data.getElement(data.getRows() - 1, data.getColumns() - 1) << endl;
}
catch (MalformedLineException ex)
{
cout << ex.getMessage();
}
c_end = clock();
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
banryu79
16-09-2008, 12:27
E per la richiesta che ho fatto nel post di risposta a Banryu? Posso ripostarle le e-mail?
OT
Il link non riesco a raggiungerlo ma avendo letto il testo delle mail la situazione mi appare chiara.
A proposito complimenti, dev'essere una bella soddisfazione :)
Vincenzo1968
16-09-2008, 12:29
Mi alleghi il file con i dati ?
Questo è il file (http://www.guidealgoritmi.it/public/post3.zip).
Ciao
Vincenzo1968
16-09-2008, 12:29
OT
Il link non riesco a raggiungerlo ma avendo letto il testo delle mail la situazione mi appare chiara.
A proposito complimenti, dev'essere una bella soddisfazione :)
Grazie :)
Questo è il file (http://www.guidealgoritmi.it/public/post3.zip).
Ciao
Compila male su Linux ;)
Compila male su Linux ;)
Ho tolto itoa (non standard) e messo una snprintf al suo posto.
v[0][0] -> 9707.6
v[99999][364] -> 7608.32
Tempo impiegato -> 23.97000 secondi
Ovviamente ottimizzando la compilazione. Core 2 Duo 2,16 Ghz
Vincenzo1968
16-09-2008, 12:51
Ho tolto itoa (non standard) e messo una snprintf al suo posto.
v[0][0] -> 9707.6
v[99999][364] -> 7608.32
Tempo impiegato -> 23.97000 secondi
Ovviamente ottimizzando la compilazione. Core 2 Duo 2,16 Ghz
Cionci scusami,
ho postato il file sbagliato(è un file di testo che contiene il mio intervento sul forum).
Purtroppo il file dei dati, anche zippato, è troppo grosso(più di 100 MB). Puoi ricostruirlo al volo con la funzione che ho postato qualche post fa.
Ciao
Vincenzo1968
16-09-2008, 12:58
Questo è il tempo sulla mia macchina:
http://www.guidealgoritmi.it/images/ImgForums/cionci.jpg
Ho tolto itoa (non standard) e messo una snprintf al suo posto.
v[0][0] -> 9707.6
v[99999][364] -> 7608.32
Tempo impiegato -> 23.97000 secondi
Ovviamente ottimizzando la compilazione. Core 2 Duo 2,16 Ghz
Il tuo con le stesse ottimizzazioni (-O3), stesso progetto e lo stesso file di dait:
Tempo impiegato -> 17.29000 secondi
array[0][0] -> 9707.6
array[99999][365] -> 0
Quindi in definitiva la differenza non è poi così immensa (soprattutto contando che il file è veramente grande). Vlae davvero la pena perdere leggibilità e manutenibilità in favore di una così risicata differenza ? Imho no. Poi casomai il file fosse dieci volte più grande se ne potrebbe anche parlare.
E quello in C++ è anche migliorabile. Basta fare un po' di profiling.
Vincenzo1968
16-09-2008, 13:23
Il tuo con le stesse ottimizzazioni (-O3), stesso progetto e lo stesso file di dait:
Tempo impiegato -> 17.29000 secondi
array[0][0] -> 9707.6
array[99999][365] -> 0
Quindi in definitiva la differenza non è poi così immensa (soprattutto contando che il file è veramente grande). Vlae davvero la pena perdere leggibilità e manutenibilità in favore di una così risicata differenza ? Imho no. Poi casomai il file fosse dieci volte più grande se ne potrebbe anche parlare.
E quello in C++ è anche migliorabile. Basta fare un po' di profiling.
Eppure, sulla mia macchina(compilatore visual studio 2008), ottengo 35 secondi contro 99.
Provo a compilare col watcom e ti faccio sapere.
xciaoatuttix
16-09-2008, 13:25
complimenti vincenzo ottime prestazioni :)
penso che in un linguaggio come il c++ le prestazioni contano eccome altrimenti che senso ha usare il c++ per complicarsi la vita.
uso python e via ;)
Vincenzo1968
16-09-2008, 13:59
complimenti vincenzo ottime prestazioni :)
penso che in un linguaggio come il c++ le prestazioni contano eccome altrimenti che senso ha usare il c++ per complicarsi la vita.
uso python e via ;)
Ciao xciaoatuttix,
grazie :)
x Cionci: ho qualche problema a compilare il tuo codice col watcom. Il mio sono riuscito a compilarlo ma ho dovuto includere gli header del c:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
using namespace std;
Il problema è nelle righe che contengono ostringstream e istringstream. Il messaggio di errore è:
sintax error; probable cause: missing ';'
Sai se c'è modo di risolvere la cosa?
P.S.
I tempi del mio codice, col watcom, scendono a 29.32800 secondi
Prova con
#include <sstream>
Vincenzo1968
16-09-2008, 14:04
Prova con
#include <sstream>
C'è già:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <ctime>
using namespace std;
:cry:
Vincenzo1968
16-09-2008, 14:09
Prova MinGW32 ;)
Cos'è? Un altro compilatore? Dove lo scarico?
Cos'è? Un altro compilatore? Dove lo scarico?
E' un porting degli strumenti GNU per Windows (fra cui il compilatore gcc).
Fai l'installazione automatica (installa g++ e gcc) e poi metti il percorso dove stanno gli eseguibili nel path.
http://www.mingw.org/
Per compilare:
g++ -O3 source.cpp -o out.exe
Oppure se vuoi puoi installare Code::Blocks che è già fornito con questo compilatore (ottimizza comunque, l'inlining con le STL fornisce un notevole boost).
Vincenzo1968
16-09-2008, 15:43
Code::Blocks installato.
Prima di riuscire a compilare stavo impazzendo perchè avevo impostato male i percorsi degli eseguibili del compilatore GCC e mi dava, giustamente, il messaggio 'compilatore non valido'.
Alla fine ce l'ho fatta e questi sono i risultati sulla mia macchina:
Il mio codice:
http://www.guidealgoritmi.it/images/ImgForums/codeblocks1.jpg
Il codice di Cionci:
http://www.guidealgoritmi.it/images/ImgForums/codeblocks2.jpg
La mia macchina è questa:
AMD Athlon(tm) 64 X2
Dual Core Processor 4800+
2.50 GHz
896 MB di RAM
:)
Abilita le ottimizzazioni del codice e togli i simboli di debug:
Build -> Select target -> Release
Project -> Build options -> seleziona Release -> Optimize for speed
Puoi ricompila ed esegui.
Vincenzo1968
16-09-2008, 15:52
Abilita le ottimizzazioni del codice e togli i simboli di debug:
Build -> Select target -> Release
Project -> Build options -> seleziona Release -> Optimize for speed
Puoi ricompila ed esegui.
Già fatto:
http://www.guidealgoritmi.it/images/ImgForums/CodeBlocksOptimize.jpg
O2 toglilo ;) Lascia solo O3, in teoria non si potrebbero usare insieme.
Comunque strana tutta questa differenza rispetto al mio. Windows lo posso solo virtualizzare come comparazione, ma intanto provo.
Vincenzo1968
16-09-2008, 16:07
O2 toglilo ;) Lascia solo O3, in teoria non si potrebbero usare insieme.
Comunque strana tutta questa differenza rispetto al mio. Windows lo posso solo virtualizzare come comparazione, ma intanto provo.
Fatto. Ottengo un guadagno di un paio di secondi per entrambi i programmi.
Fatto. Ottengo un guadagno di un paio di secondi per entrambi i programmi.
Una possibile spiegazione è la versione diversa del compilatore: su Linux ho gcc 4.2.4, mentre quella di MinGW32 è la 3.4.2 (di diversi anni fa).
Su Visual Studio hai applicato le ottimizzazioni ?
Vincenzo1968
16-09-2008, 16:31
Una possibile spiegazione è la versione diversa del compilatore: su Linux ho gcc 4.2.4, mentre quella di MinGW32 è la 3.4.2 (di diversi anni fa).
Su Visual Studio hai applicato le ottimizzazioni ?
Si. Ho provato sia con 'Maximize Speed /O2' che con 'Full Optimization /Ox' ma il risultato non cambia.
A questo punto boh...sarà merito di gcc 4, non credevo che fosse così potente nell'ottimizzazione del C++ anche rispetto a Visual Studio 2008.
complimenti vincenzo ottime prestazioni :)
penso che in un linguaggio come il c++ le prestazioni contano eccome altrimenti che senso ha usare il c++ per complicarsi la vita.
uso python e via ;)
Scelta che non sarebbe affatto da scartare...
#!/bin/python
result = []
for line in file("prova.txt"):
result.append( [float(x) for x in line.split()] )
print "Ho letto",len(result),"linee"
Ci mette sulla mia macchina circa 34 secondi, contro circa i 28 secondi del codice di cionci e i circa 9 di quello di vincenzo.
Dovendo fare le cose in C++, andrei sul semplice, e userei quello che mette gia' a disposizione la libreria standard
void read_matrix( const string& filename, vector< vector<float> >& matrix )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
matrix.push_back( vector<float>() );
istringstream is(s);
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ) );
}
}
Anche in questo caso siamo circa sui 27-28 secondi sulla mia macchina.
E non si incavola se ci metto degli spazi extra a fine riga.
Secondo me e' inutile andare a tirare fuori macchine a stati e compagnia, a meno che fare il parsing di testo sia lo scopo principale del programma, e in quel caso (presumento che il parsing sara' probabilmente piu' complicato) tanto vale farselo generare dal linguaggio (se e' in grado) oppure da un tool esterno.
banryu79
16-09-2008, 18:04
A questo punto boh...sarà merito di gcc 4, non credevo che fosse così potente nell'ottimizzazione del C++ anche rispetto a Visual Studio 2008.
[piccolo OT]
A proposito di ottimizzazione e GCC, vi posto questo interessante link, si tratta di Acovea (http://www.coyotegulch.com/products/acovea/index.html), acronimo per (Analysis of Compiler Options via Evolutionary Algorithm).
Ciao :)
xciaoatuttix
16-09-2008, 19:59
scusate ma cosa sono le ottimizzazioni del codice e o3,o2 ? mai sentito
e poi come fate a misurare il tempo ?
:stordita:
scusate l'ignoranza ma cosa sono le ottimizzazioni e o3,o2 ? mai sentito
e poi come fate a misurare il tempo ?
:stordita:
Il tempo lo misuri tramite codice, guarda il sorgente.
xciaoatuttix
16-09-2008, 20:19
Il tempo lo misuri tramite codice, guarda il sorgente.
è vero avevo guardato solo il primo codice.
e le ottimizzazioni (o3 o2 ) cosa sono? ci sono anche in g++ ? :fagiano:
e le ottimizzazioni (o3 o2 ) cosa sono? ci sono anche in g++ ? :fagiano:
Certo, SONO quelle di gcc e g++: g++ -O3 xyz.cpp -o xyz
Vincenzo1968
16-09-2008, 20:24
...
Ci mette sulla mia macchina circa 34 secondi, contro circa i 28 secondi del codice di cionci e i circa 9 di quello di vincenzo.
...
Il che vuol dire che, se devo processare un centinaio di file, il programma in Python impiega circa 56 minuti, quello di Cionci circa 45 e il mio 15. Giusto? :)
Chiaro, se tu dovessi controllare un centinaio di file diversi, ma se ne dovessi controllare uno da 1000 righe ?
Vincenzo1968
16-09-2008, 20:30
Chiaro, se tu dovessi controllare un centinaio di file diversi, ma se ne dovessi controllare uno da 1000 righe ?
In quel caso meglio Python(o C# o Java).
Vincenzo1968
16-09-2008, 20:43
Pensavo anche io inizialmente che un programma così non lungo (data la mia inesperienza) fosse estremamente lento, ma invece è molto veloce, e questo è ben accetto sopratutto in previsioni di applicazioni real-time.
...
Questo per ricordare che Mattia ha espresso le sue preferenze riguardo alla velocità del programma :)
Il che vuol dire che, se devo processare un centinaio di file, il programma in Python impiega circa 56 minuti, quello di Cionci circa 45 e il mio 15. Giusto? :)
Se il programma non fa che caricare in memoria, allora si' :D. Bisogna vedere cos'altro bisogna farci. Se il tempo di elaborazione e' dominante e il collo di bottiglia non e' nel caricamento, e' un'ottimizzazione inutile che comporta codice piu' complesso piu' difficile da mantenere. Ad esempio se come sembra deve macinare i dati in tempo reale, magari vorra' elaborare una riga alla volta. Alla macchina a stati bisogna cambiare un po' di cose, al codice "semplice" basta riutilizzare il solo ciclo interno (o in python usare i generatori per risultati ancora piu' carini).
Se il collo di bottiglia non e' nella lettura del file secondo me quelle quattrocento e passa linee di codice per leggere dei float da file sono un tantino overkill.
Vincenzo1968
17-09-2008, 11:35
Se il programma non fa che caricare in memoria, allora si' :D. Bisogna vedere cos'altro bisogna farci. Se il tempo di elaborazione e' dominante e il collo di bottiglia non e' nel caricamento, e' un'ottimizzazione inutile che comporta codice piu' complesso piu' difficile da mantenere. Ad esempio se come sembra deve macinare i dati in tempo reale, magari vorra' elaborare una riga alla volta. Alla macchina a stati bisogna cambiare un po' di cose, al codice "semplice" basta riutilizzare il solo ciclo interno (o in python usare i generatori per risultati ancora piu' carini).
Se il collo di bottiglia non e' nella lettura del file secondo me quelle quattrocento e passa linee di codice per leggere dei float da file sono un tantino overkill.
Che cos'altro si potrebbe farci? Un esempio che mi viene in mente è questo:
supponiamo che il file contenga i dati per gestire delle statistiche. Per esempio, le colonne potrebbero rappresentare i livelli di reddito e le righe gruppi di età. Il programma deve caricare in memoria la matrice e trovare la sottomatrice rettangolare di somma massima ( Contest 5 ;) ).
Anche nei casi in cui bisogna eleborare una riga per volta, non mi spaventa l'idea di dover apportare qualche modifica all'automa. Ti assicuro che anche in questo caso le prestazioni rimarrebbero migliori.
Se m'è venuta la fissazione per la velocità di esecuzione, è perchè mi sono scassato i cabasisi, in tanti anni di lavoro, a sentire gente che si lamenta della lentezza dei programmi. Già si lamenterebbero se propronessi un programma che compie il lavoro in un quarto d'ora. Figurati se ne proponessi uno che fa lo stesso lavoro in tre quarti d'ora :cry:
Ciao :)
In quel caso meglio Python(o C# o Java).
Ma mi immagino che lo debba inserire in un'applicazione già fatta in C++. Quindi queste altre scelte non sono possibili.
Bello il tuo codice marco.r, un po' troppo "insensibile" agli errori di formato, ma bello ;)
In sostanza dipende tutto dalla quantità di dati letti in input. Se fossero centinaia di MB è chiaro che un pensierino alle prestazioni bisogna farlo. Se sono pochi MB assolutamente no.
Imho bisogna, sempre, non solo in questo caso, tenere conto del giusto compromesso manutenibilità/leggibilità e prestazioni in base all'uso che ne dobbiamo fare. E ripeto: se quella parte fa da collo di bottiglia lo vedremo successivamente con un profiler: "Premature optimization is the root of all evil" (cit. Donald Knuth)
Senza contare magari arrivando all'implementazione si vede che il collo di bottiglia sta nell'accesso ai dati caricati e non nel caricamento, e la cosa sarebbe davvero comica :D
Vincenzo1968
17-09-2008, 12:20
Ma mi immagino che lo debba inserire in un'applicazione già fatta in C++. Quindi queste altre scelte non sono possibili.
Bello il tuo codice marco.r, un po' troppo "insensibile" agli errori di formato, ma bello ;)
In sostanza dipende tutto dalla quantità di dati letti in input. Se fossero centinaia di MB è chiaro che un pensierino alle prestazioni bisogna farlo. Se sono pochi MB assolutamente no.
Imho bisogna, sempre, non solo in questo caso, tenere conto del giusto compromesso manutenibilità/leggibilità e prestazioni in base all'uso che ne dobbiamo fare. E ripeto: se quella parte fa da collo di bottiglia lo vedremo successivamente con un profiler: "Premature optimization is the root of all evil" (cit. Donald Knuth)
Senza contare magari arrivando all'implementazione si vede che il collo di bottiglia sta nell'accesso ai dati caricati e non nel caricamento, e la cosa sarebbe davvero comica :D
Ciao Cionci,
si hai perfettamente ragione. Intendevo semplicemente dire che, se l'input è di dimensioni ridotte, va bene qualunque linguaggio e qualunque algoritmo. Per esempio, nel caso dell'ordinamento, andrebbe bene e, anzi forse sarebbe meglio, utilizzare il bubble sort anziché quicksort.
Riguardo alla frase di Knuth(che considero un dio nel campo della programmazione) ti vorrei far notare una cosa:
Premature optimization is the root of all evil
I tre volumi di The Art of Computer Programming (http://www-cs-faculty.stanford.edu/~knuth/taocp.html) sono un monumento alla ricerca delle massime prestazioni dei programmi.
Ciao :)
P.S.
Proprio Knuth è uno dei pionieri nel campo del parsing e della teoria degli automi. Non vedo l'ora che escano gli altri due volumi della serie e in particolar modo il quinto: Syntactic Algorithms che sarà interamente dedicato all'analisi lessicale(leggi automi a stati ;) ) e alle tecniche di parsing.
Premature optimization is the root of all evil
Appunto. Ma sono perfettamente d'accordo. Nessuno ha detto che non bisogna ottimizzare, ma bisogna farlo quando abbiamo un contesto di lavoro tipo e una prova del fatto che quella parte del codice vada ottimizzata.
Imho usare il tuo codice, per carità bello e prestante, le macchine a stati l'ho usate spesso in passato, è come sparare ad una mosca con un cannone se non lo applichiamo in un contesto preciso: cioè un'enorme quantità di dati.
Tra l'altro le macchine a stati si trovano perfettamente a proprio agio in un contesto Object Oriented: vedi lo State pattern. E fortunatamente sparisce quello switch ;)
Vincenzo1968
17-09-2008, 12:31
Appunto. Ma sono perfettamente d'accordo. Nessuno ha detto che non bisogna ottimizzare, ma bisogna farlo quando abbiamo un contesto di lavoro tipo e una prova del fatto che quella parte del codice vada ottimizzata.
Imho usare il tuo codice, per carità bello e prestante, le macchine a stati l'ho usate spesso in passato, è come sparare ad una mosca con un cannone se non lo applichiamo in un contesto preciso: cioè un'enorme quantità di dati.
Ma dovendo sviluppare un'applicazione non su commissione ma, diciamo, per il mercato, quale criterio adotteresti?
Ti baseresti sul fatto che il programma verrà probabilmente utilizzato su input di piccole dimensioni o cercheresti di ottimizzarlo al massimo?
P.S.
Che cabaso vuol dire 'imho'?
Ma dovendo sviluppare un'applicazione non su commissione ma, diciamo, per il mercato, quale criterio adotteresti?
Ti baseresti sul fatto che il programma verrà probabilmente utilizzato su input di piccole dimensioni o cercheresti di ottimizzarlo al massimo?
P.S.
Che cabaso vuol dire 'imho'?
Imho = in my humble opinion ;)
Come già detto dipende dal contesto e dal programma. Bisognerebbe stabilire un testbed tipo ed uno straordinario e vedere se ci sono problemi di prestazioni. Se ci sono prendo un profiler e vedo qual'è la parte del codice che mi fa da collo di bottiglia. A quel punto comincio ad ottimizzarla. E così avanti fino a quando non ottengo prestazioni decenti.
Vincenzo1968
17-09-2008, 13:37
Imho = in my humble opinion ;)
Come già detto dipende dal contesto e dal programma. Bisognerebbe stabilire un testbed tipo ed uno straordinario e vedere se ci sono problemi di prestazioni. Se ci sono prendo un profiler e vedo qual'è la parte del codice che mi fa da collo di bottiglia. A quel punto comincio ad ottimizzarla. E così avanti fino a quando non ottengo prestazioni decenti.
M'hai fatto venire la curiosità con questa cosa del profiler.
Propongo una specie di contest. Realizziamo un programma per un ipotetico istituto di statistica. Il programma dovrà leggere una serie di file di testo(ogni file potrebbe rappresentare, per esempio, i dati di ognuno dei comuni italiani) che contengono i dati raggruppati per livelli di reddito(le colonne) e gruppi di età(le righe).
Bisogna leggere in memoria la matrice e calcolando la media, sottrarre quest'ultima da ogni elemento della matrice ottenendo una seconda matrice con valori e positivi e negativi; altrimenti, con tutti i valori positivi, la soluzione risulterebbe banale: la somma degli elementi dell'intero array. È la stessa tecnica che si utilizza quando bisogna ricercare la brightest area di una bitmap.
Da questa seconda matrice si calcolino le sottomatrici rettangolari di somma minima e massima.
Penso che sia una cosa di interesse generale vedere come utilizzare in pratica un profiler per ottimizzare le prestazioni di un programma. :)
banryu79
17-09-2008, 13:57
Bella idea permun contest Vincenzo, potresti aprire una nuova discussione e intitolarla "Contest 6: ..." così da continuare la tradizione iniziata con GugoXX ;)
Vincenzo1968
17-09-2008, 14:12
Bella idea permun contest Vincenzo, potresti aprire una nuova discussione e intitolarla "Contest 6: ..." così da continuare la tradizione iniziata con GugoXX ;)
Ciao Banryu,
grazie.
A proposito, che fine ha fatto Gugo? È ancora in ferie? A quando il prossimo contest?
banryu79
17-09-2008, 14:18
Ciao Banryu,
grazie.
A proposito, che fine ha fatto Gugo? È ancora in ferie? A quando il prossimo contest?
Non ne ho idea, è da un po' che non lo leggo più sul Forum, in effetti :boh:
Ma mi immagino che lo debba inserire in un'applicazione già fatta in C++. Quindi queste altre scelte non sono possibili.
Bello il tuo codice marco.r, un po' troppo "insensibile" agli errori di formato, ma bello ;)
Hai, ragione, ma non ci vuole molto a gestirli, basta abilitare le eccezioni, e decidere come gestirle. Se lo stream trova qualcosa che non e' un float viene lanciata un'eccezione. Quel che manca e' "solo" decidere dove raccoglierla. Trattandosi di una lettura di un laser probabilmente si tratta di una sequenza temporale, in tal caso basta raccogliere subito l'eccezione e morta li'.In caso contrario si puo' farlo nel loop piu' esterno.
Ad esempio si puo' fare qualcosa del tipo
void read_matrix( const string& filename, vector< vector<float> >& matrix )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
try
{
matrix.push_back( vector<float>() );
istringstream is(s);
is.exceptions( ifstream::badbit | ifstream::failbit );
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ) );
if ( matrix.back().size() != 365 )
matrix.pop_back();
} catch( ifstream::failure e )
{ /* Ignore wrong line */ }
}
}
In questo caso eliminiamo anche le righe che non hanno la lunghezza giusta e siamo a posto. Un po' meno chiaro di prima ma ancora abbastanza leggibile.
Vincenzo1968
17-09-2008, 15:48
Hai, ragione, ma non ci vuole molto a gestirli, basta abilitare le eccezioni, e decidere come gestirle. Se lo stream trova qualcosa che non e' un float viene lanciata un'eccezione. Quel che manca e' "solo" decidere dove raccoglierla. Trattandosi di una lettura di un laser probabilmente si tratta di una sequenza temporale, in tal caso basta raccogliere subito l'eccezione e morta li'.In caso contrario si puo' farlo nel loop piu' esterno.
Ad esempio si puo' fare qualcosa del tipo
void read_matrix( const string& filename, vector< vector<float> >& matrix )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
try
{
matrix.push_back( vector<float>() );
istringstream is(s);
is.exceptions( ifstream::badbit | ifstream::failbit );
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ) );
if ( matrix.back().size() != 365 )
matrix.pop_back();
} catch( ifstream::failure e )
{ /* Ignore wrong line */ }
}
}
In questo caso eliminiamo anche le righe che non hanno la lunghezza giusta e siamo a posto. Un po' meno chiaro di prima ma ancora abbastanza leggibile.
E la gestione delle eccezioni, con i blocchi try-catch è, tu m'insegni, pesante dal punto di vista delle prestazioni. Giusto?
Vincenzo1968
17-09-2008, 16:17
E la gestione delle eccezioni, con i blocchi try-catch è, tu m'insegni, pesante dal punto di vista delle prestazioni. Giusto?
Sbagliato!
Ho provato le due versioni(con e senza gestione delle eccezioni) e impiegano lo stesso tempo(circa 98 secondi).
Ma guarda cosa succede con il seguente file:
2.025e+12 3.125e-15 2.125e-5
1.0125e-10 2.ciao 5.12548e-12
Nota nella seconda riga, seconda colonna, il 'numero' 2.ciao
Il tuo programma non segnala l'errore e la seguente riga di codice:
cout << "v[1][1] -> " << matrix[1][1] << endl;
da questo output:
v[1][1] -> 2
E' normale per come gestisce la conversione lo stream, ma l'errore dovrebbe appare sicuramente sull'elemento successivo.
Vincenzo1968
17-09-2008, 16:29
E' normale per come gestisce la conversione lo stream, ma l'errore dovrebbe appare sicuramente sull'elemento successivo.
No, non segnala nessunissimo errore.
Con quest'altro file:
2.025e+12 3.125e-15 2.125e-5
1.0125e-10 ciao 5.12548e-12
il programma va, semplicemente, in crash.
Vincenzo1968
17-09-2008, 16:36
http://www.guidealgoritmi.it/images/ImgForums/Marco.jpg
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <ctime>
using namespace std;
void read_matrix1( const string& filename, vector< vector<float> >& matrix )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
matrix.push_back( vector<float>() );
istringstream is(s);
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ) );
}
}
void read_matrix2( const string& filename, vector< vector<float> >& matrix )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
try
{
matrix.push_back( vector<float>() );
istringstream is(s);
is.exceptions( ifstream::badbit | ifstream::failbit );
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ) );
if ( matrix.back().size() != 365 )
matrix.pop_back();
} catch( ifstream::failure e )
{ /* Ignore wrong line */ }
}
}
int main()
{
clock_t c_start, c_end;
c_start = clock();
vector< vector<float> > matrix;
read_matrix2("C:\\Temp\\test1.txt", matrix);
cout << endl;
cout << "v[0][0] -> " << matrix[0][0] << endl;
cout << "v[1][1] -> " << matrix[1][1] << endl;
c_end = clock();
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
eh, dovrei provare il codice prima di postarlo :asd:, soprattutto sulle cose che e' un po' che non guardo :p.
C'e' un errore, anzi due.
Il primo e' che quando raccolgo l'eccezione dovrei eliminare l'array parzialmente letto:
catch( ifstream::failure e )
{ matrix.pop_back(); }
L'altro errore e' che mi ero dimenticato che comunque istringstream quando si "ferma" segnala un failbit e non un eofbit ( :confused: ), per cui lancia ogni volta un'eccezione.
Purtroppo l'unica e cambiare un po' il codice e passare ad una lettura "normale" :p :(
void read_matrix( const string& filename, vector< vector<float> >& matrix, int line_size )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
istringstream is(s);
try
{
matrix.push_back( vector<float>(line_size) );
is.exceptions( ios::badbit | ios::failbit );
for ( int i=0 ; i<line_size ; ++i )
{
is >> matrix.back()[i];
}
is.exceptions( ios::goodbit );
// Be sure that there isn't anything left on the line...
string s;
if ( is >> s )
{
matrix.pop_back();
}
} catch( const ifstream::failure& e )
{
matrix.pop_back();
}
}
}
nota 1 : probabilmente prima il programma crashava perche' la seconda linea veniva letta solo in parte (sforavi quindi il vector).
nota 2 : ovviamente a questo punto possiamo pure fare a meno delle eccezioni. Non cambia comunque poi molto
void read_matrix( const string& filename, vector< vector<float> >& matrix, int line_size )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
istringstream is(s);
matrix.push_back( vector<float>(line_size) );
for ( int i=0 ; i<line_size ; ++i )
{
if ( ! (is >> matrix.back()[i]) )
{
matrix.pop_back();
continue;
}
}
// Be sure that there isn't anything left on the line...
string s;
if ( is >> s )
{
matrix.pop_back();
}
}
}
Peccato solo non sia piu' tanto carina come quella iniziale :( :cry:
Vincenzo1968
17-09-2008, 18:10
Marco,
purtroppo crasha ancora. Forse non ho capito bene l'utilizzo del terzo parametro della funzione. Devo passargli 3 nel caso di un array con tre colonne, giusto?
Ciao
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <ctime>
using namespace std;
void read_matrix1( const string& filename, vector< vector<float> >& matrix )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
matrix.push_back( vector<float>() );
istringstream is(s);
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ) );
}
}
void read_matrix2( const string& filename, vector< vector<float> >& matrix )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
try
{
matrix.push_back( vector<float>() );
istringstream is(s);
is.exceptions( ifstream::badbit | ifstream::failbit );
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ) );
if ( matrix.back().size() != 365 )
matrix.pop_back();
} catch( ifstream::failure e )
{ /* Ignore wrong line */ }
}
}
void read_matrix3( const string& filename, vector< vector<float> >& matrix, int line_size )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
istringstream is(s);
matrix.push_back( vector<float>(line_size) );
for ( int i=0 ; i<line_size ; ++i )
{
if ( ! (is >> matrix.back()[i]) )
{
matrix.pop_back();
continue;
}
}
// Be sure that there isn't anything left on the line...
string s;
if ( is >> s )
{
matrix.pop_back();
}
}
}
int main()
{
clock_t c_start, c_end;
c_start = clock();
vector< vector<float> > matrix;
read_matrix3("C:\\Temp\\test1.txt", matrix, 3);
cout << endl;
cout << "v[0][0] -> " << matrix[0][0] << endl;
cout << "v[1][1] -> " << matrix[1][1] << endl;
c_end = clock();
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
occhio che quello e' il codice che avevo scritto come esempio per gestire il primo caso che avevo esposto (ovvero quello in cui si preferisce saltare la linea errata piuttosto che rinunciare alla lettura dell'intero file). Se fai un controllo molto probabilmente ti trovi che matrix.size() e' 1, per cui con il secondo output sfori. Ovviamente ci sono anche altre alternative, tipo lasciare una riga vuota, copiare la precedente etc., dipende come vuoi gestirlo.
Ma mi immagino che lo debba inserire in un'applicazione già fatta in C++. Quindi queste altre scelte non sono possibili.
Bello il tuo codice marco.r, un po' troppo "insensibile" agli errori di formato, ma bello ;)
Mi devo ri-correggere, il codice iniziale si puo' benissimo sistemare con poco, una volta che uno si ricorda bene come funzionano gli istream_iterator :D.
void read_matrix( const string& filename, vector< vector<float> >& matrix, int line_size )
{
string s;
ifstream input( filename.c_str() );
while ( getline( input, s ) )
{
istringstream is(s);
matrix.push_back( vector<float>() );
copy( istream_iterator<float>( is ),
istream_iterator<float>(),
back_inserter( matrix.back() ));
// Did we read the right amount of values, and consumed all the input ?
string s;
if ( matrix.back().size() != line_size || (is >> s) )
{
matrix.pop_back();
}
}
}
uff... sto cominciando ad invecchiare :stordita:, devo fare le cose con meno fretta :p
banryu79
18-09-2008, 12:36
uff... sto cominciando ad invecchiare :stordita:, devo fare le cose con meno fretta :p
Ma in genere non sono i giovani che corrono come dannati? :D
Però ad esempio risulterebbe complicato segnalare la posizione dell'errore ;)
Però ad esempio risulterebbe complicato segnalare la posizione dell'errore ;)
Perche' ? La posizione dell'errore e' la lunghezza del vector appena letto, per la riga basta tenere un contatore.
Ma in genere non sono i giovani che corrono come dannati? :D
Vuol dire che mi sto "rinfanciullendo" ? :D
Vincenzo1968
18-09-2008, 12:58
Ohé Cionci,
ciao.
Ho modificato i programmi in modo da fargli calcolare la media dei numeri dell'intero file senza caricare l'array in memoria.
Questo è il mio codice:
#include <iostream>
#include <ctime>
using namespace std;
#define BUFFER_SIZE 4096
typedef enum tagStati
{
S_ERROR = -1, S0 = 0, S1, S2, S3, S4, S5, S6, S7, S8, S9
} Stati;
Stati DFA(const char *szFileName, double *media)
{
Stati stato = S0;
FILE *fp;
unsigned char buffer[BUFFER_SIZE];
int numblocks;
int numread;
unsigned char c;
int k, x, j;
int riga, colonna;
char szNum[256];
double sum = 0;
int count = 0;
unsigned char byteCR = 0xD; // Carriage Return
unsigned char byteLF = 0xA; // Line Feed
*media = 0;
fp = fopen(szFileName, "rb"); // Warning C4996 -> Usare fopen_s
if ( fp == NULL )
{
cout << "Errore nell'apertura del file " << szFileName << endl;
return S_ERROR;
}
if ( fseek(fp, 0, SEEK_END) )
return S_ERROR;
numblocks = ftell(fp)/BUFFER_SIZE;
if ( numblocks == 0 )
{
numblocks = 1;
}
else
{
if ( ftell(fp) % BUFFER_SIZE != 0 )
numblocks++;
}
fseek(fp, 0, SEEK_SET);
numread = fread(buffer, 1, BUFFER_SIZE, fp);
riga = colonna = 0;
x = k = j = 0;
while ( x < numblocks )
{
c = *(buffer + k++);
if ( c == byteCR )
{
if ( k >= numread )
{
numread = fread(buffer, 1, BUFFER_SIZE, fp);
k = 0;
x++;
}
c = *(buffer + k++);
}
switch (stato)
{
case S0:
j = 0;
if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S1;
}
else if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S2;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S3;
}
else if ( c == ' ' || c == '\t' )
{
while ( c == ' ' || c == '\t' )
{
c = *(buffer + k++);
if ( k >= numread )
break;
}
k--;
}
else
{
cout << "Errore: stato S0 << riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S1:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S2;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S3;
}
else
{
cout << "Errore: stato S1 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S2:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
}
else if ( c == '.' )
{
szNum[j++] = c;
stato = S4;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S5;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
sum += atof(szNum);
count++;
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S2 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S3:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else
{
cout << "Errore: stato S3 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S4:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S7;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
sum += atof(szNum);
count++;
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S4 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S5:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S8;
}
else
{
cout << "Errore: stato S5 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S6:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S6;
}
else if ( c == 'E' || c == 'e' )
{
szNum[j++] = c;
stato = S7;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
sum += atof(szNum);
count++;
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S6 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S7:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == '-' || c == '+' )
{
szNum[j++] = c;
stato = S8;
}
else
{
cout << "Errore: stato S7 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
case S8:
case S9:
if ( c >= '0' && c <= '9' )
{
szNum[j++] = c;
stato = S9;
}
else if ( c == ' ' || c == '\t' || c == byteLF )
{
szNum[j] = '\0';
sum += atof(szNum);
count++;
if ( c == byteLF )
{
riga++;
colonna = 0;
}
else
{
colonna++;
}
stato = S0;
}
else
{
cout << "Errore: stato S9 riga " << riga << " colonna " << colonna << endl;
fclose(fp);
return S_ERROR;
}
break;
}
if ( k >= numread )
{
numread = fread(buffer, 1, BUFFER_SIZE, fp);
k = 0;
x++;
}
}
fclose(fp);
if ( stato == S2 || stato == S4 || stato == S6 || stato == S9 )
{
szNum[j] = '\0';
sum += atof(szNum);
count++;
}
*media = sum/count;
return stato;
}
int main()
{
Stati stato;
double media;
clock_t c_start, c_end;
char *szFileName = "C:\\Temp\\test3.txt";
c_start = clock();
stato = DFA(szFileName, &media);
c_end = clock();
if ( stato == S0 || stato == S2 || stato == S4 || stato == S6 || stato == S9 )
cout << endl << "media -> " << media << endl;
else
cout << "L'automa ha restituito un errore." << endl;
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
e questo è il risultato:
http://www.guidealgoritmi.it/images/ImgForums/AutomaMedia.jpg
Ho tentato di modificare il tuo codice:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <ctime>
using namespace std;
class MalformedLineException
{
int row;
int column;
string message;
public:
MalformedLineException(int row, int column)
{
this->row = row;
this->column = column;
ostringstream oss;
oss << "Malformed line at row " << row << " and column " << column;
message = oss.str();
}
string getMessage()
{
return message;
}
int getRow()
{
return row;
}
int getColumn()
{
return column;
}
};
int countColumns(string line)
{
istringstream iss(line);
int columnCounter = 0;
while (1)
{
float tmp;
iss >> tmp;
if (iss.fail() && !iss.eof())
throw MalformedLineException(1, columnCounter + 1);
columnCounter++;
if (iss.eof())
break;
}
return columnCounter;
}
int main()
{
clock_t c_start, c_end;
int riga, colonna;
double media, sum;
int count;
int colonne;
c_start = clock();
ifstream inputFile("C:\\Temp\\test3.txt");
if (inputFile.fail())
{
cout << "Error opening file" << endl;
return 1;
}
try
{
string line;
riga = colonna = 0;
sum = 0;
count = 0;
while (!inputFile.fail())
{
getline(inputFile, line);
riga++;
colonne = countColumns(line);
istringstream iss(line);
for (int i = 0; i < colonne; ++i)
{
float f;
iss >> f;
if (iss.fail())
throw MalformedLineException(riga, i + 1);
sum += f;
//cout << "num -> " << f << endl;
count++;
sum += f;
}
}
media = sum/count;
//cout << "count -> " << count << endl;
cout << endl << "media -> " << media << endl;
}
catch (MalformedLineException ex)
{
cout << ex.getMessage();
}
c_end = clock();
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
Purtroppo da un messaggio di errore:
http://www.guidealgoritmi.it/images/ImgForums/CionciMedia.jpg
Sembra che tenti di leggere oltre l'ultima riga del file. Cosa ho sbagliato?
Ciao.
Sinceramente non capisco perché tu gli voglia far calcolare la media. Diventa chiaro che in quel caso c'è un altro collo di bottiglia, cioè il vector che contiene le righe.
Edit: ho visto ora che stai tentando di creare la media in tempo reale. Ora guardo
Vincenzo1968
18-09-2008, 13:08
Se il programma non fa che caricare in memoria, allora si' :D. Bisogna vedere cos'altro bisogna farci. Se il tempo di elaborazione e' dominante e il collo di bottiglia non e' nel caricamento, e' un'ottimizzazione inutile che comporta codice piu' complesso piu' difficile da mantenere. Ad esempio se come sembra deve macinare i dati in tempo reale, magari vorra' elaborare una riga alla volta. Alla macchina a stati bisogna cambiare un po' di cose, al codice "semplice" basta riutilizzare il solo ciclo interno (o in python usare i generatori per risultati ancora piu' carini).
Se il collo di bottiglia non e' nella lettura del file secondo me quelle quattrocento e passa linee di codice per leggere dei float da file sono un tantino overkill.
Ecco perchè. Volevo provare a elaborare una riga alla volta e senza caricare l'array in memoria.
:)
Vincenzo1968
18-09-2008, 13:10
Sinceramente non capisco perché tu gli voglia far calcolare la media. Diventa chiaro che in quel caso c'è un altro collo di bottiglia, cioè il vector che contiene le righe.
Edit: ho visto ora che stai tentando di creare la media in tempo reale. Ora guardo
ehm, scusa... ma quale vector? :confused:
ehm, scusa... ma quale vector? :confused:
Leggi l'edit...mi sono reso conto che stavi facendo la media in tempo reale ;)
Vincenzo1968
18-09-2008, 13:24
Ho provato su un file di piccole dimensioni:
5.23 7.28 21.5
8.9 10.5 8.3
e ho visto che il problema è nel new-line dell'ultima riga. Se lo togli non da il messaggio di errore ma il calcolo della media è sbagliato. Praticamente legge due volte l'ultima riga e calcola la media su nove numeri anziché sei.
edit: l'automa funziona sia col new-line che senza ;)
Vincenzo1968
18-09-2008, 13:24
Leggi l'edit...mi sono reso conto che stavi facendo la media in tempo reale ;)
Si, scusami. Me ne sono accorto dopo :)
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <ctime>
using namespace std;
class MalformedLineException
{
int row;
int column;
string message;
public:
MalformedLineException(int row, int column)
{
this->row = row;
this->column = column;
ostringstream oss;
oss << "Malformed line at row " << row << " and column " << column;
message = oss.str();
}
string getMessage()
{
return message;
}
};
int countColumns(string line)
{
istringstream iss(line);
int columnCounter = 0;
while (1)
{
float tmp;
iss >> tmp;
if (iss.fail() && !iss.eof())
throw MalformedLineException(1, columnCounter + 1);
columnCounter++;
if (iss.eof())
break;
}
return columnCounter;
}
void parseLine(string line, int columns, double &sum)
{
istringstream iss(line);
for (int i = 0; i < columns; ++i)
{
float f;
iss >> f;
if (iss.fail())
throw MalformedLineException(0, i + 1);
sum += f;
}
}
int main()
{
clock_t c_start, c_end;
c_start = clock();
ifstream inputFile("/media/deposito/CartellaVbox/test.txt");
if (inputFile.fail())
{
cout << "Error opening file" << endl;
return 1;
}
try
{
string line;
getline(inputFile, line);
int columns = countColumns(line);
double sum = 0.0;
int counter = 0;
while (!inputFile.fail())
{
parseLine(line, columns, sum);
counter += columns;
getline(inputFile, line);
}
cout << endl;
cout << "Sum: " << sum << endl;
cout << "Average: " << sum / counter << endl;
}
catch (MalformedLineException ex)
{
cout << ex.getMessage();
}
c_end = clock();
printf("\nTempo impiegato -> %5.5f secondi\n", (double)(c_end - c_start) / CLOCKS_PER_SEC);
return 0;
}
In questo modo la mia applicazione ci mette 23.25s, la tua 15.53s.
In ogni caso continuo a non vedere quale utilità abbia questa prova ;)
Vincenzo1968
18-09-2008, 14:33
Sulla mia macchina:
AMD Athlon(tm) 64 X2
Dual Core Processor 4800+
2.50 GHz
896 MB di RAM
i tempi sono questi:
http://www.guidealgoritmi.it/images/ImgForums/AutomaMedia2.jpg
http://www.guidealgoritmi.it/images/ImgForums/CionciMedia2.jpg
Vincenzo1968
18-09-2008, 14:39
...
In questo modo la mia applicazione ci mette 23.25s, la tua 15.53s.
In ogni caso continuo a non vedere quale utilità abbia questa prova ;)
Marco aveva espresso qualche dubbio sulle prestazioni dell'automa per applicazioni in tempo reale. :)
Marco aveva espresso qualche dubbio sulle prestazioni dell'automa per applicazioni in tempo reale. :)
Secondo me non ha comunque senso un confronto del genere: se l'applicazione in tempo reale passa l'1% del suo tempo a leggere ed elaborare quei dati è assolutamente inutile ottimizzare ;)
Vincenzo1968
18-09-2008, 14:52
Secondo me non ha comunque senso un confronto del genere: se l'applicazione in tempo reale passa l'1% del suo tempo a leggere ed elaborare quei dati è assolutamente inutile ottimizzare ;)
Giusto!
E se, invece, debbo elaborare un centinaio di file per delle statiche, per esempio, l'automa sbriga il lavoro in un terzo del tempo ;)
E se, invece, debbo elaborare un centinaio di file per delle statiche, per esempio, l'automa sbriga il lavoro in un terzo del tempo ;)
Sicuramente.
Vincenzo1968
18-09-2008, 15:39
Compilato col watcom impiega soltanto 19.21900 secondi :)
A proposito di questo compilatore e dei problemi che ho avuto nel compilare il tuo codice, sembra che non supporti direttamente le STL.
Bisogna scaricare questo:
http://www.stlport.org/
compilare la libreria e seguire le istruzioni per l'installazione. ;)
A proposito di questo compilatore e dei problemi che ho avuto nel compilare il tuo codice, sembra che non supporti direttamente le STL.
Bisogna scaricare questo:
http://www.stlport.org/
compilare la libreria e seguire le istruzioni per l'installazione. ;)
Allora non lo fare nemmeno, ti immagini che prestazioni la STL non essendo ottimizzata per il compilatore :D
Vincenzo1968
18-09-2008, 16:36
Allora non lo fare nemmeno, ti immagini che prestazioni la STL non essendo ottimizzata per il compilatore :D
Ci ho provato ma non ci sono riuscito. Se qualcuno sa come fare, please, posti la soluzione :)
Comunque, almeno per quanto riguarda il C, Watcom mi sembra un gran bel compilatore. Anche se non sempre gli eseguibili risultano più veloci. In uno dei contest, ricordo che visual studio generava un eseguibile più veloce.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.