Komplexe Zahlen aus Datei einlesen



  • Hallo!

    Ich bin neu hier und daher noch relativ unerfahren was den Umgang im Forum entspricht.
    Ich habe folgendes Problem: ich würde gerne Zahlen aus einer Datei einlesen (vorzugsweise zwei Zahlen pro Zeile als float mit Leerzeichen getrennt) um diese dann als Real- und Imaginärteil einer komplexen Zahl zuzuordnen. Ich habe bis jetzt nur Erfahrung mit C und Fortran, würde aber eine "korrekte" Lösung in C++ sehr begrüßen.

    Vielen Dank für Eure Hilfe!



  • Hallo Poolshark,

    willkommen im C++-Forum.

    Wenn Real- und Imaginärteil durch Leerzeichen getrennt sind, ist dies wohl die einfachste Lösung:

    #include <fstream>
    #include <iostream>
    #include <complex>
    
    int main()
    {
        using namespace std;
        ifstream datei( "input.txt" );
        if( !datei.is_open() )
        {
            cerr << "Fehler beim Oeffnen der Datei" << endl;
            return -1;
        }
        for( double re, im; datei >> re >> im; )
        {
            complex< double > c( re, im );
            // mache was mit 'c' ...
            cout << "gelesen: " << c << endl;
        }
        return 0;
    }
    

  • Administrator

    std::ifstream input("...");
    
    float real, img;
    std::vector<std::complex<float> > vec;
    
    while(input >> real >> img)
    {
      vec.push_back(std::complex<float>(real, img));
    }
    

    Sofern es wirklich nur ein File ist, welches auf jeder Zeile zwei Zahlen hat und die erste Zahl jeweils die reelle Zahl ist. Die Streams ignorieren standardmässig Whitespaces. Zudem kann man einen Stream direkt auf seine Gültigkeit prüfen. Es wird somit jeweils zwei Zahlen probiert zu lesen, solange dies geht, wird eine komplexe Zahl erzeugt und in den Vektor kopiert. Sobald das Lesen fehlschlägt, sofern das File richtig formatiert ist, haben wir das Ende erreicht.

    Ein Link zu einer C++ Referenz befindet sich in meiner Signatur.

    Grüssli



  • google topics:
    c++ ifstream zum einlesen (getline() falls du strings auseinanderfummeln willst ansonsten >>, << float/double überladung
    c++ complex zum apspeichern
    c++ vector (std::vector<std::complex<float> >) zum abspeichern mehrerer Dinge

    edit:: boah bin ich langsam, danke 🙂 orrigiert



  • padreigh schrieb:

    c++ vector (std::vectorstd::complex >)

    Dravere schrieb:

    std::vector<std::complex<float> > vec;
    

    Wieso nutzt ihr einen vector, um Daten unbekannter Größe zu speichern? Eine std::deque ist doch viel besser geeignet.



  • Eine std::deque ist doch viel besser geeignet.

    Begründung? 🕶



  • VF schrieb:

    padreigh schrieb:

    c++ vector (std::vectorstd::complex >)

    [...] Daten unbekannter Größe [...] std::deque ist doch viel besser geeignet.

    Bei mir: Gewohnheit, habe mit Vector mehr gearbeitet. Im Normalfall pack ich da ein std::vector<Whatever>.reserve(amount); davor und vermeide damit re-allocs. 😉



  • kommt halt drauf an - aber anhören tut es sich erst mal so, als ob das einlesen relativ zeitunkritisch passieren würde - außerdem sind 8Byte pro Objekt jetzt nicht so unendlich viel zu kopieren, dass es die x zusätzlichen new`s und die langsamere iteration rechtfertigen würde.
    außerdem ists ja nicht so, dass die eingabe aus nem wahnsinnig schnellen medium ausgelesen werden würde - nein, sie kommt von ner festplatte...

    bb


  • Administrator

    1. Man liest einmal ein. Es müssten schon verdammt viele Zahlen sein, bis man hier überhaupt einen Geschwindigkeitsnachteil hat. Dafür hat man wirklich schnellen Zugriff auf die Daten.
    2. Ein std::vector vergrössert sich auch nicht immer nach jedem push_back . Somit braucht es wahrscheinlich nur ein paar mal eine neue Speicherreservierung mit Kopien.
    3. Falls man wirklich grössere Datenmenge lädt, kann man womöglich eine Abschätzung machen, wieviele es sein werden, und dann std::vector::reserve verwenden.

    In den meisten Fällen ist std::vector völlig ausreichend.

    Grüssli



  • Und ich meine. Bleibt der Flaschenhals nicht egal bei welchem Container hier in jedem Fall das Dateisystem? Dann ist die Diskussion nämlich von vornerein erschlagen.


  • Mod

    Außerdem hatten wir hier im Forum schon zigmal das Thema deque vs. vector mit zahlreichen Benchmarks diskutiert. Mal nach suchen. vector hat jedenfalls immer klar vorne gelegen außer in ganz speziellen Fällen.



  • So, ich habe jetzt ein bisschen herumexperimentiert...
    Leider funktioniert (zumindest bei mir) der 1. angegebene Code nicht. Vielleicht hat es ja was mit meiner Entwicklerumgebung zu tun (ich benutze XCode).
    Anyway, ich kann mittlerweile Zahlen aus einem File mittels ifstream auslesen allerdings geht das immer nur für eine Zeile? Wie kann man nun alle Zeilen auslesen?

    Hier der Code:

    #include <fstream> 
    #include <iostream> 
    #include <complex>
    
    using namespace std;
    
    int main() 
    { 
    
    	int a,b;
    
    	ifstream datei("input.txt");
    
        for( int c, d; datei >> c >> d; ) {
    
    	//datei >> c >> d;
    
    	a=c+1;
    	b=d+1;
    
    	cout << "Test: ";
    	cout << a << b;
    	cout << " orginal: ";
    	cout << c << d;
    	cout << "\n";
    
    	}
    
    }
    

    Die Ausgabe beschränkt sich auf folgendes:
    Test: 44 orginal: 34

    In meiner Testdatei "input.txt" befinden sich 3 Zeilen mit folgenden Werten:
    `3 4

    5 6

    7 8`

    Vielen Dank für die vielen prompten Antworten!


  • Mod

    Poolshark schrieb:

    So, ich habe jetzt ein bisschen herumexperimentiert...
    Leider funktioniert (zumindest bei mir) der 1. angegebene Code nicht.

    Was meinst du mit funktioniert nicht?

    Vielleicht hat es ja was mit meiner Entwicklerumgebung zu tun (ich benutze XCode).

    Sehr unwahrscheinlich, denn der Code ist absolut in Ordnung und es ist sehr, sehr ungewöhnlich Fehler in Entwicklungsumgebungen zu finden. Besonders bei solch kleinen Progrämmchen.

    Anyway, ich kann mittlerweile Zahlen aus einem File mittels ifstream auslesen allerdings geht das immer nur für eine Zeile? Wie kann man nun alle Zeilen auslesen?

    Das sollte so eigentlich auch funktionieren. Bei mir liefert dein Programm auch ein vollständiges Ergebnis:

    Test: 23 orginal: 12
    Test: 45 orginal: 34
    Test: 67 orginal: 56
    Test: 89 orginal: 78
    

    input.txt:

    1 2
    3 4
    5 6
    7 8
    

    Mir fällte jedoch auf, dass dein Programm schon falsch rechnet, weil die 4 nicht um eins erhöht wurde. Daher vermute ich mal, dass du mit einem etwas anderem Programm gearbeitet hast als das hier gezeigte.



  • probiere mal spaßeshalber ab Zeile 14

    char black_magic;
        for( int c, d; datei >> c >> d >> black_magic; ) {
    

    .. und sage uns was passiert



  • Also ich habe den Code nun etwas verändert:

    #include <fstream> 
    #include <iostream> 
    #include <complex>
    
    using namespace std;
    
    int main(void) 
    { 
    
    	int a,b,c,d;
    
    	ifstream datei("input.txt");
    
        while (!datei.eof()) {
    		datei >> c >> d;
    		a=c+1;
    		b=d+1;
    
    		cout << "Test: ";
    		cout << a << b;
    		cout << " orginal: ";
    		cout << c << d;
    		cout << "\n";
    	}
    
    }
    

    Leider beschränkt sich die Ausgabe immer noch auf eine Zeile:
    `Last login: Tue Oct 5 16:42:33 on ttys000

    /Users/florianragossnig/Documents/Uni/Computational\ Physics/Programme/Fourier/build/Debug/Fourier ; exit;

    Florian-Ragossnigs-MacBook-Pro:~ florianragossnig$ /Users/florianragossnig/Documents/Uni/Computational\ Physics/Programme/Fourier/build/Debug/Fourier ; exit;

    Test: 45 orginal: 34

    logout

    [Process completed]`

    Immerhin rechnet das Programm jetzt richtig...
    Ich denke nicht dass es an der Entwicklungsumgebung generell liegt, aber evtl. verwende ich den falschen Compiler (obwohl ich ein C++ Projekt gestartet habe)!

    Bei Abänderung des Codes zu dem Beitrag von Werner passiert, kurz und knapp, garnichts:
    `Last login: Tue Oct 5 16:44:09 on ttys000

    /Users/florianragossnig/Documents/Uni/Computational\ Physics/Programme/Fourier/build/Debug/Fourier ; exit;

    Florian-Ragossnigs-MacBook-Pro:~ florianragossnig$ /Users/florianragossnig/Documents/Uni/Computational\ Physics/Programme/Fourier/build/Debug/Fourier ; exit;

    logout

    [Process completed]`



  • Aus Performancegründen solltest du die Zahlen binär speichern außer die Speicherung als ASCII ist unbeding erforderlich...



  • wie gesagt sollte der code aber richtig sein...
    bist du mal mit dem debugger durchgegangen?

    bb

    edit: @icematrix: gut, dass das jz richtig viel mit dem Thema zu tun hat... 4 Zahlenpaare... stimmt - da kann man einige Stunden Rechenzeit sparen...


  • Mod

    Icematix schrieb:

    Aus Performancegründen solltest du die Zahlen binär speichern außer die Speicherung als ASCII ist unbeding erforderlich...

    Aus Portabilitätsgründen solltest du die Zahlen als ASCII speichern, außer die Speicherung als binär ist unbeding erforderlich...


  • Mod

    Poolshark schrieb:

    Bei Abänderung des Codes zu dem Beitrag von Werner passiert, kurz und knapp, garnichts:

    Es scheint mir, deine Eingabedatei hat nur eine Zeile. Überprüfe diese Möglichkeit. Vielleicht liest du versehentlich die falsche Datei ein. Ändere mal die Datei von der du meinst, dass sie eingelesen wird und guck, ob die Änderungen Auswirkungen auf das Programm haben.



  • Hab den Fehler gefunden: Die von Xcode produzierte executable funktioniert aus irgendwelchen Gründen nicht... Wenn ich das Programm in der Debugger Console laufen lasse bekomme ich die richtigen Lösungen. Da ich keine Ahnung habe was XCode da alles macht und da der Code zu stimmen scheint, dürfte dies vorerst ausreichen.

    Vielen Dank für Eure Hilfe ( es könnte sein dass ich mich bezüglich der komplexen Rechenoperationen nocheinmal an euch wenden muss 😉 )!


Anmelden zum Antworten