Auslesen von komplexen Zahlen aus einer Datei



  • Und Z. 22+23 ?

    Und kannst du mal erklären, inwiefern das Ergebniss falsch ist ?



  • Hacker schrieb:

    Und Z. 22+23 ?

    Und kannst du mal erklären, inwiefern das Ergebniss falsch ist ?

    Ich habe es Mal mit folgendem Quellcode getestet. Das Ergebnis ist falsch, da jeder ausgelesene Wert gleich ist, als würde er die gleiche Zeile 74370 Mal auslesen.

    Weiterhin müsste a+b = 74370 sein. a = 1 und b = 1. Also irgendetwas stimmt da nicht...

    //ließt alle Werte nach <tag attributeName ....>
    vector<complex<double> > readComplexNumbers(const char* filename,const char* tag, const char* attributeName){
        vector<complex<double> > complexNumbers;
        ifstream f(filename);
    
            //solange Zeilen ignorieren, bis der Tag gefunden wurde
        while(!isAttributeTag(f,tag,attributeName)){
            f.ignore( numeric_limits< streamsize >::max(), '\n' );
        }
            //die Zeile des Tags ebenso ignorieren
        f.ignore( numeric_limits< streamsize >::max(), '\n' );
    
            //nun Werte lesen
        double real, imag;
        char plus, j, vorzeichen; 
        int a = 0;
        int b = 0;
         for(int p=0; p<74370; p++){   
               if(f>>real>>plus>>j>>imag){
                     if(plus == '-'){
                         imag *= -1;
                     }
                     a++;
                 }
                 if(f>>real){
                     imag=0;
                     b++;
                 }
    //             cout<<complex<double>(real,imag);
                 complexNumbers.push_back(complex<double>(real,imag)); 
         } 
        cout<<endl<<a<<endl<<b<<endl;
        return complexNumbers; 
    }
    


  • Hast du mal den Fehlerstatus des Streams überprüft?



  • 314159265358979 schrieb:

    Hast du mal den Fehlerstatus des Streams überprüft?

    Ich weiß nicht wie man das macht oder was das sein soll.

    Doch denke ich eher das der Fehler in der Ausleseroutine liegt.

    z.B. ist der Code defintiv falsch, da das 2. if immer gegeben ist...

    if(f>>real>>plus>>j>>imag){
                     if(plus == '-'){
                         imag *= -1;
                     }
                     a++;
                 }
                 if(f>>real){
                     imag=0;
                     b++;
                 }
    


  • Der Fehler besteht darin, dass deine Einleseroutine immer abwechselnd Zahlen mit und ohne Imaginärteil einliest.



  • Ich weiß nicht wie man das macht oder was das sein soll.

    Du weisst nicht wie das geht ? RTFM ? Kom schon.

    Es gibt verschiedene Member-Methoden (von ifstream) für Fehlerprüfung:

    good() - true, wenn alles funktioniert hat. (Edit: Du kannst auch DeinIfstream statt DeinIfstream.good() schreiben.)
    fail() - Gegenteil, gibt false zurück, wenn alles ordnungsgemäß ablief, bei Schreib- oder Lesefehlern aber true.
    bad() - Wenn gravierende Fehler vorliegen, die den Stream komplett funktionsuntüchtig machen.

    Hast du schon exceptions gemacht ?



  • Das mit dem Fehlerstatus war Unfug, tut er ja schon mit if. Er liest einfach falsch ein.



  • 314159265358979 schrieb:

    Der Fehler besteht darin, dass deine Einleseroutine immer abwechselnd Zahlen mit und ohne Imaginärteil einliest.

    Aber das soll ja Sinn und Zweck dieser Funktion sein. Wenn ich nur komplexe Zahlen hätte, dann würde die Funktion auch tadellos funktionieren.

    Die Problemstellung ist ja gerade eine Funktion zu entwerfen, welche sowohl reale als auch komplexe Zahlen in einen complex vector schreibt.



  • Und wenn auf komplexe eine weitere komplexe folgt, krachts.



  • Probier mal mit einem else vor dem if in zeile 7 (dein letzter Code) aus.
    Das dürfte das Problem beheben.



  • Hacker schrieb:

    Probier mal mit einem else vor dem if in zeile 7 (dein letzter Code) aus.

    Nöp.



  • 314159265358979 schrieb:

    Und wenn auf komplexe eine weitere komplexe folgt, krachts.

    Und wieso? Bzw. wie ist denn dieses Problem zu beheben zu umgehen?

    Wenn ich statt if(...), else hinschreibe ist das Ergebnis leider immer noch falsch.

    vector<complex<double> > readComplexNumbers(const char* filename,const char* tag, const char* attributeName){
        vector<complex<double> > complexNumbers(7770);
        ifstream f(filename);
    
            //solange Zeilen ignorieren, bis der Tag gefunden wurde
        while(!isAttributeTag(f,tag,attributeName)){
            f.ignore( numeric_limits< streamsize >::max(), '\n' );
        }
            //die Zeile des Tags ebenso ignorieren
        f.ignore( numeric_limits< streamsize >::max(), '\n' );
    
            //nun Werte lesen
        double real, imag;
        char plus, j, vorzeichen; 
        int a = 0;
        int b = 0;
         for(int p=0; p<7770; p++){   
               if(f>>real>>plus>>j>>imag){
                     if(plus == '-'){
                         imag *= -1;
                     }
                     a++;
                 }
                 else{
                     imag=0;
                     b++;
                 }
     //            cout<<complex<double>(real,imag);
                    complexNumbers[p]=complex<double>(real,imag);
         } 
        cout<<endl<<a<<endl<<b<<endl;
        return complexNumbers; 
    }
    


  • NAIN,

    else if(f>>real){
                     imag=0;
                     b++;
                 }
    

    mit der Bedingung von vorher.



  • Denk doch mal nach. Was ist das nächste, wenn eine reele Zahl eingelesen wurde? Entweder ein Imaginärteil, oder eine weitere Zahl. (reel oder komplex) Du musst irgendwie erkennen, was gerade gelesen wird.
    Hackers Vorschlag ist, wenn mich nicht gerade alles täuscht, falsch.



  • Hacker schrieb:

    NAIN,

    else if(f>>real){
                     imag=0;
                     b++;
                 }
    

    mit der Bedingung von vorher.

    Funktioniert leider alles nicht. Wie gesagt ich habe bereits alles versucht.

    Die Einleseroutine muss grundsätzlich falsch sein und ich weiß nicht warum?!

    Denk doch mal nach. Was ist das nächste, wenn eine reele Zahl eingelesen wurde? Entweder ein Imaginärteil, oder eine weitere Zahl. (reel oder komplex) Du musst irgendwie erkennen, was gerade gelesen wird.
    Hackers Vorschlag ist, wenn mich nicht gerade alles täuscht, falsch.

    Wenn eine reele Zahl eingelesen wurde, dann springt er doch in die nächste Zeile und schaut ist diese komplex oder reel usw. usw.

    Es ist ja immer eine Zahl pro Zeile vorhanden (also entweder komplex oder reel).



  • Nein, er schaut eben nicht, ob. Er liest solange ein, bis es fehlschlägt. Das ist dann der Zeitpunkt, an dem eine zweite komplexe Zahl kommt. Dann machts kabumm.



  • 314159265358979 schrieb:

    Nein, er schaut eben nicht, ob. Er liest solange ein, bis es fehlschlägt. Das ist dann der Zeitpunkt, an dem eine zweite komplexe Zahl kommt. Dann machts kabumm.

    Und wie krieg ich es hin, dass es funktioniert?!



  • Gleich mal vorweg: Eine Komplettlösung bekommst du von mir nicht. Aber ich kann dir Hilfestellung geben. Ich habe das Gefühl, du hast die C++ Streams noch nicht so ganz verstanden, insbesondere, was if(stream >> xy) tut, daher hier mal ein paar Erklärungen.

    Ein Stream hat, wie von Hacker schon erwähnt, 3 Zustände. Beim parsen ist aber letztendlich egal, ob der Fehler aufgrund eines Hardwareproblems oder des Dateiendes ist, daher werden wir uns nur um die Zustände "good" und "bad" kümmern.

    Ein if, wie dieses hier...

    double x;
    if(is >> x)
    

    ...bedeutet: Lies vom Stream einen Wert vom Typ double nach x ein, danach überprüfe auf Fehler. Wenn alles gut gegangen ist, wird der Block nach dem if ausgeführt (der Stream befindet sich im good-Zustand) Bei einem Lesefehler bleibt der Stream, was die Daten betrifft, unverändert, lediglich das failbit wird gesetzt. In einem else-Zweig könntest du eine Exception werfen, oder andere Arten von Fehlerbehandlung durchführen.

    Weiters: Du kannst Zeichen nur ein einziges mal aus einem Stream lesen. Was du rausnimmst, bekommst du kein zweites mal heraus. Zurücklegen geht im Normalfall auch nicht. Deshalb funktioniert dein Ding mit 2 if nicht, ebensowenig das von Hacker mit else if.

    Auch zu empfehlen ist die Referenz: http://www.cplusplus.com/reference/iostream/istream/
    Interessante Funktionen könnten für dich get und getline sein. Vielleicht auch noch putback, es gibt viele verschiedene Herangehensweisen.

    Und hier noch die Erklärung, was bei deinem Code passiert. (Ich habe alles etwas verkürzt, um die relevanten Teile hervorzuheben.)

    double real, imag;
    char plus, j;
    
    // Wir nehmen an, im Stream befindet sich "-1.0+j2.0\n3.0-j4.0"
    for(int p = 0; p < 7770; ++p)
    {  
        // hui, hier passiert viel. realteil weg: "+j2.0\n3.0-j4.0"
        // plus weg: "j2.0\n3.0-j4.0"
        // j weg: "2.0\n3.0-j4.0"
        // und schließlich der Imaginärteil: "\n3.0-j4.0"
        // bis hier stimmts
        if(f >> real >> plus >> j >> imag)
        {
            ...
        } // ein else-zweig würde nur ausgeführt werden, wenn beim einlesen ein fehler auftreten würde
    
        // im stream steht: "\n3.0-j4.0"
        // realteil weg (\n wird einfach überlesen): "-j4.0"
        // "-j4.0" bleibt übrig und kann beim nächsten schleifendurchlauf nicht geparst werden. mist.
        if(f >> real)
        {
            ...
        }
    }
    

    Ich hoffe ich habe damit alle Klarheiten beseitigt. Wenn was klar sein wollte, einfach nachfragen 😉



  • Ersteinmal vielen Dank für die ausführliche Antwort. Ich denke ich habe es jetzt tatsächlich ein wenig besser verstanden. Eigentlich müsste der Quellcode so meiner Ansicht nach funktionieren, aber das tut er nicht.

    Besonders verblüfft mich, dass er nur 389 Mal in die if-Bedingung springt (also a=389) und b=7381. Jedoch müsste es eigentlich genau umgekehrt sein!

    Es sind zu 95% komplexe Zahlen, die restlichen 5% sind reele Zahlen, von daher stimmt wieder irgendetwas nicht...

    Mein Quellcode sieht nun so aus:

    double real, imag;
        char plus, j; 
        int a = 0;
        int b = 0;
         for(int p=0; p<7770; p++){
    // f>>real findet jedes Mal statt, ganz egal ob die kommende Zahl reel oder komplex ist, falls sie komplex ist, dann wird im "if" weiter gemacht, ansonsten springt er zu else
               if(f>>real>>plus>>j>>imag){
                     if(plus == '-'){
                         imag *= -1;
                     }
                     a++;
                 }
                 else{
                     imag=0;
                     b++;
                 }
                    complexNumbers[p]=complex<double>(real,imag);
         }
    


  • Finde es ja lustig, dass ich den Code hier wider sehe. Ich dachte, da sProgrmam würde jetzt im Müll liegen und niemand würde es mehr brauchen 🙄

    und lass dir nichts von Hacker einreden. du brauchst kein reserve. push_back war toll. Ich weiß schon, was ich tue 🙄

    um dir bei deinem Problem zu helfen:

    Was glaubst du, was passiert, wenn deine Eingabe so aussieht:

    1.345
    1.678+j901
    

    und du

    f>>real>>plus>>j>>imag;
    

    anwendest?
    naja:
    real=1.345
    plus=1
    j=.
    imag=678

    und ab dann ließt du nur noch Müll ein.

    Tipp: ließ zuerst real ein und dann schau nach, ob im übernächstne zeichen ein j steht. du kannst mit peek() schauen, wie das nächste zeichen aussieht ohne es zu lesen.


Anmelden zum Antworten