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
-
Der Code kompiliert bei mir einwandfrei. Sollte auch keine Probleme machen in C++, da es für
cosh
,sinh
undexp
Überladungen fürfloat
unddouble
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
undexp
Überladungen fürfloat
unddouble
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)))’
-
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
-
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
undcosh
das Ergebnis der Operation indouble
zu konvertieren. Keine Ahnung wie der auf diese bescheuerte Idee kommt. Wenn man die Berechnung voncosh
undsinh
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
undcosh
das Ergebnis der Operation indouble
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
-
<cmath>
hatte ich dazugefügt, wird allerdings mit<complex>
beim GCC dazugefügt. Allerdings ist das Problem wirklich dasusing
. Beim MSVC wird alles im globalen Namensraum deklariert und dann in den Namensraumstd
mitusing
hineingezogen. Hatte ich ganz vergessen, dass dies nicht dem Standard entsprichtWobei 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.