complex<>



  • #include <complex>
    #include <iostream>
    
    typedef float my_float;
    // typedef double my_float;
    
    int main()
    {
      std::complex<my_float> c(1.0,1.0);
    
      std::cout << (c / 2.0) << std::endl; // (*)
    
      return 0;
    }
    

    Wenn my_float vom Typ double ist, funktioniert der Code. Falls my_float vom Typ float ist, geht Zeile (*) nicht mehr, weil 2.0 anscheinend ein double ist und der op/ dann nicht mehr definiert ist.

    Wie kann ich Zeile (*) schreiben oder wie kann ich das Problem umgehen, so dass der Code in beiden Fällen funktioniert?



  • std::cout << ( c / 2.0f ) << std::endl;
    


  • Danke. Das ging ja fix. Vielleicht habe ich zu viel vereinfacht. Hier mal ein realitätsnahes Beispiel mit ein bisschen Physik:

    my_float om = 0.1, k = 1.0, draft = 5.0, h = 1000.0, xmin=200.0;
      std::complex<my_float> waveVecx(1.0, 10.0);
      std::complex<my_float> waveVecy(1.0, 10.0);
      std::complex<my_float> CI(0.0,1.0);
    
      std::complex<my_float> vyWave = om * waveVecy / CI / k * cosh( k * (draft/2.0f-h)) / sinh(k * h) * exp(xmin*waveVecx);
    

    Problematisch sind hier anscheinend die drei Funktionen cosh, sinh und exp


  • Administrator

    Der Code kompiliert bei mir einwandfrei. Sollte auch keine Probleme machen in C++, da es für cosh , sinh und exp Überladungen für float und double gibt. Einziges Problem könnte die Initialisierung deiner Variablen darstellen, aber das resultiert höchstens in einer Warnung.

    Grüssli



  • Erst denken, dann fragen:

    std::complex<my_float> vyWave = om * waveVecy / CI / k * my_float(cosh( k * (draft/2.0f-h)) / sinh(k * h)) * exp(xmin*waveVecx);
    

    scheint zu gehen. Auch wenn das leider nicht zu einer erhöhten Lesbarkeit des Codes führt, wenn sowas häufiger auftaucht.



  • Dravere schrieb:

    Der Code kompiliert bei mir einwandfrei. Sollte auch keine Probleme machen in C++, da es für cosh , sinh und exp Überladungen für float und double gibt. Einziges Problem könnte die Initialisierung deiner Variablen darstellen, aber das resultiert höchstens in einer Warnung.

    Grüssli

    Huch, das überrascht mich.

    #include <complex>
    #include <iostream>
    
    typedef float my_float;
    
    int main()
    {
      my_float om = 0.1, k = 1.0, draft = 5.0, h = 1000.0, xmin=200.0;
      std::complex<my_float> waveVecx(1.0, 10.0);
      std::complex<my_float> waveVecy(1.0, 10.0);
      std::complex<my_float> CI(0.0,1.0);
    
      std::complex<my_float> vyWave = om * waveVecy / CI / k * cosh( k * (draft/2.0f-h))  / sinh(k * h) * exp(xmin*waveVecx);
    
      return 0;
    }
    

    führt zu

    xxxxxx@yyyyyy:test g++ complex.cpp -ocomplex
    complex.cpp:16:2: warning: no newline at end of file
    complex.cpp: In function ‘int main()’:
    complex.cpp:13: error: no match for ‘operator*’ in ‘std::operator/ [with _Tp = float](((const std::complex<float>&)((const std::complex<float>*)(& std::operator/ [with _Tp = float](((const std::complex<float>&)((const std::complex<float>*)(& std::operator* [with _Tp = my_float](((const my_float&)((const my_float*)(& om))), ((const std::complex<float>&)((const std::complex<float>*)(& waveVecy))))))), ((const std::complex<float>&)((const std::complex<float>*)(& CI))))))), ((const float&)((const float*)(& k)))) * cosh(((double)(((draft / 2.0e+0f) - h) * k)))’
    

  • Administrator

    Der Cast ist völlig unnötig, wenn dein Kompiler eine korrekte Standardbibliothek hat. Und die Zeile ist schon so oder so unleserlich. Am besten setzt du Zwischenergebnisse ein, um die Leserlichkeit zu erhöhen.

    Edit: In Bearbeitung ... zu viele Posts zu schnell hintereinander ...

    Grüssli


  • Administrator

    Ok, sorry für den Doppelpost, aber nur mit dem Edit sieht man nicht, dass was neues da ist.

    Anscheinend weiss der GCC Kompiler nichts besseres zu tun, als vor dem Übergeben an sinh und cosh das Ergebnis der Operation in double zu konvertieren. Keine Ahnung wie der auf diese bescheuerte Idee kommt. Wenn man die Berechnung von cosh und sinh aus der Zeile rausnimmt und vorher ausrechnet, dann geht es wunderbar:

    float r0 = sinh(k * h);
    float r1 = cosh(k * (draft / 2.0f - h));
    
    std::complex<my_float> vyWave = om * waveVecy / CI / k * r1 / r0 * exp(xmin*waveVecx);
    

    Spricht auf der anderen Seite dafür, dass man Zwischenergebnisse verwenden sollte 😉

    Grüssli



  • Dravere schrieb:

    Anscheinend weiss der GCC Kompiler nichts besseres zu tun, als vor dem Übergeben an sinh und cosh das Ergebnis der Operation in double zu konvertieren.

    Das liegt wohl daran, dass sinh und cosh mit
    `

    double sinh(double);

    double cosh(double);

    `
    zufällig aus der C-Library sichtbar sind. Ich sehe hier kein <cmath> und auch keine std::-Qualifizierung bzw using-Deklarationen. Richtig müsste es doch so aussehen, nicht?

    #include <complex>
    #include <cmath>      // <--- !!!
    #include <iostream>
    
    typedef float my_float;
    
    int main()
    {
      using std::cosh;  // <--- !!!
      using std::sinh;  // <--- !!!
      using std::exp;   // <--- !!!
      my_float om = 0.1, k = 1.0, draft = 5.0, h = 1000.0, xmin=200.0;
      std::complex<my_float> waveVecx(1.0, 10.0);
      std::complex<my_float> waveVecy(1.0, 10.0);
      std::complex<my_float> CI(0.0,1.0);
    
      std::complex<my_float> vyWave = om * waveVecy / CI / k *
        cosh( k * (draft/2.0f-h))  / sinh(k * h) * exp(xmin*waveVecx);
    
      return 0;
    }
    

    kk


  • Administrator

    <cmath> hatte ich dazugefügt, wird allerdings mit <complex> beim GCC dazugefügt. Allerdings ist das Problem wirklich das using . Beim MSVC wird alles im globalen Namensraum deklariert und dann in den Namensraum std mit using hineingezogen. Hatte ich ganz vergessen, dass dies nicht dem Standard entspricht 🙂

    Wobei ich mich trotzdem frage, wieso der Fall mit den Zwischenergebnissen dann funktioniert? Führt er dann zweimal eine implizite Konvertierung durch? Einmal nach double, was ja kein Problem ist, und einmal nach float, was ich zumindest für warnungsberechtigt halten würde 😕

    Grüssli



  • Ah, jetzt kapiere ich. Vielen dank!

    ps:

    @Dravere: So längliche Formeln finde ich nicht schön, Zwischenergebnisse aber (oft) noch unschöner. In so einer Formel ist jede größe physikalisch, sowohl links als auch rechts. Wenn man jetzt formal unphysikalische Zwischenergebnisse einführt, stört das den Lesefluss auch ganz erheblich.


Log in to reply