Erstellung eines Histogramms



  • Hey Leute 🙂 !

    Kann mir wirklich gut vorstellen, wie genervt man sein muss, wenn ständig neue Benutzer ohne vorherige Recherchen hier nach Hilfe suchen...
    Ich bin leider auch einer davon, nur habe ich bereits mein Bestes (soweit es geht) gegeben und komme zu keiner Lösung 😞
    Es geht darum, ein Histogramm zu erstellen; ich lese eine Datei mit 2 Spalten ein, in der ersten steht die Zeit und in der zweiten die Ortskoordinate.
    Dann Überprüfe ich ob die gewählten Intervalle getroffen wurden und lasse mir am Ende den "counter" ausgeben.
    Die Sache ist, dass ich selbst bei einer "simplen" Datei mit Daten wie:
    1 1
    2 2
    3 1
    4 4
    5 1
    6 6
    7 1
    8 8
    9 1

    am Ende in der Ausgabe totalen Schwachsinn bekomme mit Werten von:

    #intervall Auftritte_Teilchen
    0 -1732826976
    1 32767
    2 -1732826961
    3 32767
    4 311044592
    5 32720
    6 307760984
    7 32720
    8 -1732826912
    9 32767

    herausbekomme. Bin ziemlich ratlos bei der Fehlersuche, weil ich mir nicht erklären kann woher solche Zahlen kommen sollen. Greife ich da vielleicht irgendwo auf falschen Speicher zu?

    ...also falls dies doch gegen Forumvorschriften verstößt, so ignoriert den Beitrag einfach.

    Wenn nicht, dann hier der Quellcode, bin für jede Hilfe oder jeden Tipp sehr dankbar! 🙄

    Wie gesagt, ich habe wenig Erfahrung bisher, mein Stil ist möglicherweise nicht der Beste 😃

    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <cstring>
    
    using namespace std;
    
    const int N=10; //Anzahl Intervalle
    
    int main(int argc, char** argv){
    if(argc != 2) {
    		cout << "Erwartet Dateiname als Parameter" << endl;
    		return 0;
    	}
    	char buf[256];
    	ifstream fl;
    	fl.open(argv[1]);
    	if(!fl.is_open()) {
    		return 1;
    	}
    	double max = 0;
    	double min = 0;
    	while(!fl.eof()) {
    		fl.getline(buf, 255);
    
    		double x;
    		char* pch;
    		pch = strtok(buf, " ");
    		if(pch != NULL)
    			x = atoi(pch);
    
    		if(x > max)
    			max = x;  //Setzen der Grenzen des betrachteten Bereichs
    
    		if(x < min)
    			min = x;
    	}
    
    	double intervallgroesse = (max-min)/N; //Intervallgröße bestimmen
    	double intervallbeginn[N];	
    	for(int i=0; i<N; i++){
    		intervallbeginn[i]=intervallgroesse*(i); //Berechnung des jeweiligen Beginns eines Intervalls
    		}
    
    	fl;
    	fl.open(argv[1]);
    	if(!fl.is_open()) {
    		return 1;
    	}
    	int counter[N]; //Zähler der Auftritte des Teilchen im Intervall i
    	while(!fl.eof()) {
    		fl.getline(buf, 255);
    
    		double x;
    		char* pch;
    		pch = strtok(buf, " ");
    		if(pch != NULL)
    			x = atoi(pch);
    		int i=0;
    		if(x>intervallbeginn[i]){i++;} //Falls x größer als Intervallbeginn i, nächstes Intervall betrachten
    		else{counter[i-1]++;} //Wenn x nicht größer als Intervallbeginn des aktuellen Intervalls, muss es im vorherigen Intervall sein
    
    	}
    	ofstream out("histogramm.txt");
    	out<<"#intervall"<<" "<<"Auftritte_Teilchen"<<endl;  //Ausgabe
    	for(int i=0; i<N; i++){
    	out<< i << " " << counter[i] <<endl;
    	}
    	fl.close();
    	out.close();
    
    	return 0;
    }
    


  • Musst du nicht atof benutzen, wenn du
    double x;
    verwendest?
    Oder andersrum, warum deklarierst du nicht einfach
    int x;
    wenn scheinbar ohnehin nur integers in Frage kommen.



  • Ich übersehe da mal einiges und frage gleich: Willst du nur Ganzzahlen oder auch Kommazahlen einlesen?



  • Ich möchte auch Kommazahlen einlesen.



  • crack123 schrieb:

    Ich möchte auch Kommazahlen einlesen.

    Versuch mal operator >>. Du kannst von ifstreams lesen wie von std::cin:

    ifstream is("file.txt");
    double max;
    is >> max; // Eventuell Rückgabewert beachten
    

    Hilft dir das? 🙂

    (atoi() gibt im Übrigen eine Ganzzahl, genauer einern Integer zurück!)



  • Servus, ich kämpfe aktuell auch mit Histogrammen. Ohne vorher den Thread gelesen zu haben, ich bin mit den Histogrammen der GSL sehr zufrieden, siehe: http://www.gnu.org/s/gsl/manual/html_node/Histograms.html



  • Hallo crack123,

    Die Hauptfehler bestehen darin, dass in den Zeilen 63,63 die Schleife fehlt, die das passende Intervall findet. Weiter ist das Array counter[] in Zeile 51 nicht initialisiert. D.h. da steht vorher irgendwas drin und das wird später ausgegeben. Daher die komischen Werte.

    crack123 schrieb:

    Wie gesagt, ich habe wenig Erfahrung bisher, mein Stil ist möglicherweise nicht der Beste 😃

    ok - das ist verständlich, jeder war mal Anfänger.

    Aber wo hast Du denn das

    crack123 schrieb:

    while(!fl.eof()) {
    		fl.getline(buf, 255);
    

    gelernt?

    Gruß
    Werner

    @Edit benutzte den 'C/C++'-Tag statt des 'Code'-Tags um den Sourcecode darzustellen - sieht besser aus



  • Heyhey,
    erstmal riesengroßes Dankeschön an all die Leute die versuchen, mir zu helfen, hätte keine so große Hilfsbereichtschaft erwartet.
    Klasse Forum habt ihr hier, ich werde wohl länger bleiben 🙄

    @Werner Salomon: ich glaube ich verstehe was in Zeile 63 schief gelaufen ist, aber komme momentan auf keine Lösung. Ein kleiner Tipp vielleicht? 🤡
    Und ehm was genau meinst Du mit "das Array ist nicht initialisiert"?
    Mache ich nicht gerade das mit int counter[n]? 😃

    while(!fl.eof()) {
            fl.getline(buf, 255);
    

    Das habe ich irgendwo im Internet gefunden als ich mich mit dem Einlesen von Dateien beschäftigt hab, ich weiß die Quelle nicht mehr 😉



  • Hallo,

    bezogen auf die Initialisierung:
    mittels "int counter[N]" wird für eine lokale Variable nur Speicher bereitgestellt (ohne die Inhalte zu verändern, d.h. dort stehen also zufällige Werte drin).
    Mittels

    int counter[N] = { 0 };
    

    kannst du dies aber erzwingen (d.h. alle Array-Werte werden auf 0 gesetzt).



  • Aaaaaaaah ja stimmt, dämlich von mir.

    Danke dafür!

    ...

    Hab alles was ich brauchte, Thread kann sterben! 😃

    Vielen Dank nochmal an alle die geholfen haben!



  • crack123 schrieb:

    Hab alles was ich brauchte, Thread kann sterben! 😃

    na - noch nicht ganz; ich bin Dir noch eine Antwort schuldig.

    crack123 schrieb:

    while(!fl.eof()) {
            fl.getline(buf, 255);
    

    Das habe ich irgendwo im Internet gefunden als ich mich mit dem Einlesen von Dateien beschäftigt hab, ich weiß die Quelle nicht mehr 😉

    Du weißt, dass geschätzte 90% von dem, was man im Internet findet, Mist ist? In diesem Thread habe ich schon mal versucht auszuführen, warum ich diese while-!EOF-Konstruktion für einen Fehler halte.

    In Deinem Fall kannst Du die Zahlen z.B. einfach mit ..

    for( double zeit, ort; fl >> zeit >> ort; )
        {
            if( zeit < min )
                min = zeit;
            if( zeit > max )
                max = zeit;
        }
    

    .. einlesen. Wenn Du doubles haben willst, so lese doubles - so einfach ist das.

    Gruß
    Werner


Log in to reply