Definition von complex ?
-
Werner Salomon schrieb:
welche Funktionalität hat Deine Klasse, die std::complex nicht hat?
Es hat zusätzlich die Funktionen
.getphase()
.getamplitude()
.setphase(const double)
.setamplitude(const double)Das hat den Vorteil das eine Funktion die ein CComplex zurückgibt, gleichzeit auch die Phase ausgeben kann als
double phase = DataClass.getvalue().phase()Mit std::complex kann ich zwar auch phase und amplitude erhalten aber nicht als Funktion der Klasse (in std::complex sind es "arg" und "abs").
Matthias
-
pospiech schrieb:
Es hat zusätzlich die Funktionen
.getphase()
.getamplitude()
.setphase(const double)
.setamplitude(const double)Das hat den Vorteil das eine Funktion die ein CComplex zurückgibt, gleichzeit auch die Phase ausgeben kann als
double phase = DataClass.getvalue().phase()Hallo Matthias,
das funktioniert doch mit std::complex genauso:
double phase = arg( DataClass.getvalue() );
pospiech schrieb:
Mit std::complex kann ich zwar auch phase und amplitude erhalten aber nicht als Funktion der Klasse (in std::complex sind es "arg" und "abs").
Wo ist da denn das Problem? double hat ja auch keine Methode sin()!
Dass das Setzen von einzelnen Werte keine gute Idee ist, habe ich am 11.09 schon versucht darzustellen.
Werner Salomon schrieb:
Das Setzen einzelner Größen ist nicht vorgesehen und macht auch keinen Sinn. Man kann natürlich eine komplexe Zahl mit einer anderen überschreiben, also etwa so
complex< double > d = polar( abs( c ), 45.0 * PI/180. ); // gleicher Betrag wie c mit Phase 45Grad
Das Verlangen, die Werte einzeln zu setzen resultiert im Allgemeinen aus einem Designfehler. Erklär' doch mal, wozu Du das Setzen von Amplitude und Phase benötigst.
Gruß
Werner
-
Werner Salomon schrieb:
Das Verlangen, die Werte einzeln zu setzen resultiert im Allgemeinen aus einem Designfehler. Erklär' doch mal, wozu Du das Setzen von Amplitude und Phase benötigst.
Ich beschreibe ein elektromagentisches Feld mit a * exp(i phi), also eine Komplexe Zahl mit den Informationen Amplitude und Phase. Da ich dabei die Werte Amplitude und Phase einzelne Abfragen und Manipulieren muss sind für mich diese Funktionen von enormem Vorteil.
Warum es keinen sinn machen sollte bei gleicher Phase die Amplitude zu ändern oder umgekehrt erschließt sich mir überhaupt nicht. Insbesondere da es die mathemtatische Operation ist die ich dauernd benötige.
Matthias
-
pospiech schrieb:
Warum es keinen sinn machen sollte bei gleicher Phase die Amplitude zu ändern oder umgekehrt erschließt sich mir überhaupt nicht. Insbesondere da es die mathemtatische Operation ist die ich dauernd benötige.
Ok .. mal ganz konkret. Wie sieht die Operation aus, bei der die Amplitude bei unveränderter Phase gesetzt werden muss. Wie wird dieser Wert für die Amplitude in diesem Fall bestimmt?
-
Werner Salomon schrieb:
pospiech schrieb:
Warum es keinen sinn machen sollte bei gleicher Phase die Amplitude zu ändern oder umgekehrt erschließt sich mir überhaupt nicht. Insbesondere da es die mathemtatische Operation ist die ich dauernd benötige.
Ok .. mal ganz konkret. Wie sieht die Operation aus, bei der die Amplitude bei unveränderter Phase gesetzt werden muss. Wie wird dieser Wert für die Amplitude in diesem Fall bestimmt?
Ich bestimme das in meiner Klasse so:
inline double phase(){ return atan2(this->im,this->re);}; // atan2(x,y) = atan(x/y) inline double amplitude(){ return sqrt(this->re*this->re+this->im*this->im);}; inline void setphase(double phase) { double CurrAmpl; CurrAmpl = amplitude(); this->re = CurrAmpl * cos(phase); this->im = CurrAmpl * sin(phase); } inline void setamplitude(double amplitude) { double CurrPhase; CurrPhase = phase(); this->re = amplitude * cos(CurrPhase); this->im = amplitude * sin(CurrPhase); }
wobei es mathematisch sowies kein Problem ist, da ich von einer Komplexen Zahl immer Amplitude oder Phase bestimmen kann und über c = a *exp(i phi) immer beides setzen kann.
Unsinnig wird es nur bei Amplitude = 0 die Phase zu setzen.
Matthias
-
Hallo Matthias,
Ich habe mich vielleicht unklar ausgedrückt. Meine Frage war wo - bzw. in welchem Kontext - z.B. dieses 'setamplitude()' aufgerufen wird, und wie der Parameter 'amplitude' vor dem Aufruf bestimmt wurde. Ist dieser Wert von 'amplitude' von dem ursprünglichen Wert der komplexen Zahl (this->re; this->im) irgendwie abhängig?
Gruß
Werner
-
Werner Salomon schrieb:
Ist dieser Wert von 'amplitude' von dem ursprünglichen Wert der komplexen Zahl (this->re; this->im) irgendwie abhängig?
Ich habe 2D Arrays dieser Komplexen Zahlen und setze die Amplitude der Complexen Zahlen in der Regel anhand einer Formel(x,y). Die gesetzten Werte sind damit nicht von dem vorherigen Wert der Complexen Zahl abhängig.
Matthias
-
Um die Amplitude einer komplexen Zahl zu aendern muss man sie doch einfach mit einem entsprechenden Faktor multiplizieren, wenn ich jetzt nicht voellig auf dem Schlauch stehe. Ganz ohne ableiten und ganz ohne cos()-sin() rumspielen sieht das dann so aus:
template<typename T, typename U> void SetAmplitude(std::complex<T>& val, U amp) { val *= amp/val.amplitude(); }
Bezeichnet man val (vorher) mit v, die amplitude (vorher) mit a, val (nachher) mit v' und amp mit a', dann schreibt sich das so:
/edit: wenn die gesetzten Werte wie du sagst garnicht vom vorherigen Wert der Zahl abhaengig sind, impliziert das, dass du nicht nur die Amplitude aenderst, sondern auch die Phase. Dann muesstest du allerdings die neue Phase mit angeben.
-
pumuckl schrieb:
wenn die gesetzten Werte wie du sagst garnicht vom vorherigen Wert der Zahl abhaengig sind, impliziert das, dass du nicht nur die Amplitude aenderst, sondern auch die Phase. Dann muesstest du allerdings die neue Phase mit angeben.
Die Amplitude die ich setzen möchte hängt nicht davon ab. Dieser Wert ändert beim Setzten nicht die Phase, aber natürlich den Real und Imaginärteil. Aber wozu diese ganze mathemtische Diskussion dienen soll ist mir noch immer unklar.
Matthias
-
Werner Salomon schrieb:
Dass das Setzen von einzelnen Werte keine gute Idee ist, habe ich am 11.09 schon versucht darzustellen.
Werner Salomon schrieb:
Das Setzen einzelner Größen ist nicht vorgesehen und macht auch keinen Sinn. Man kann natürlich eine komplexe Zahl mit einer anderen überschreiben, also etwa so
complex< double > d = polar( abs( c ), 45.0 * PI/180. ); // gleicher Betrag wie c mit Phase 45Grad
Das Verlangen, die Werte einzeln zu setzen resultiert im Allgemeinen aus einem Designfehler. Erklär' doch mal, wozu Du das Setzen von Amplitude und Phase benötigst.
Warum sollte das ein Designfehler sein? Was ist schlimm daran, wenn ich eine Phasenverschiebung durchführen will? Oder nur die Amplitude ändern möchte? Ist ein sinnvoller Algorithmus, der das tun möchte wirklich unvorstellbar?
-
pumuckl schrieb:
Um die Amplitude einer komplexen Zahl zu aendern muss man sie doch einfach mit einem entsprechenden Faktor multiplizieren, wenn ich jetzt nicht voellig auf dem Schlauch stehe.
ja und genau darum geht es hier eben NICHT. Matthias möchte nicht z.B. die Amplitude um den Faktor 2 vergrößern - klar das erreicht man auch durch Multiplikation der komplexen Zahl mit 2 - sondern Matthias möchte eine setAmplitude-Methode (s. sein Posting vom 19.02 23:47).
Ich behaupte nun - aus Erfahrung mit solchen Werten und aus einem Bauchgefühl heraus - das eigentliche Problem steckt woanders.
Jester schrieb:
Warum sollte das ein Designfehler sein? Was ist schlimm daran, wenn ich eine Phasenverschiebung durchführen will? Oder nur die Amplitude ändern möchte? Ist ein sinnvoller Algorithmus, der das tun möchte wirklich unvorstellbar?
Es ist nicht schlimm, die Amplitude zu verändern, sondern es ist meistens ein Hinweis auf ein Problem woanders, wenn man sie neu Setzen möchte.
pospiech schrieb:
Ich habe 2D Arrays dieser Komplexen Zahlen und setze die Amplitude der Complexen Zahlen in der Regel anhand einer Formel(x,y). Die gesetzten Werte sind damit nicht von dem vorherigen Wert der Complexen Zahl abhängig.
Die Amplitude die ich setzen möchte hängt nicht davon ab. Dieser Wert ändert beim Setzten nicht die Phase, aber natürlich den Real und Imaginärteil. Aber wozu diese ganze mathemtische Diskussion dienen soll ist mir noch immer unklar.
Hallo Matthias,
Ich versuche mal - zusammen mit dem was Du uns bisher mitgeteilt hast - meine Glaskugel zu befragen.Ich vermute: Du hast zwei 2D-Arrays; eines mit den Werten für die Amplitude und eines mit den Werten für die Phase. Jetzt musst Du diese Werte irgendwie da rausholen, um mit ihnen zu arbeiten. Dazu hast Du an zwei Codestellen eine doppelte Schleife (über x und über y des jeweiligen 2D-Arrays) und schaufelst dort jeweils getrennt einmal Amplitude und einmal Phase in Deine Struktur oder Klasse.
Wenn das so sein sollte, dann liegt der von mir vorher erwähnte 'Designfehler' bereits in der Tatsache, dass es diese beiden 2D-Arrays anstatt eines 2D-Arrays mit komplexen Werten gibt.
Dieser Umstand führt nämlich zu doppeltem Code (zwei mal zwei Schleifen), der auch noch redundant ist - es wird ja jedesmal im Prinzip das gleiche getan. Und genau diese sollte man bei der Programmierung vermeiden. Daher nenne ich das Designfehler. Das ist jetzt nichts Schlimmes - hat aber evt. Folgen - wie das Verlangen nach einer Set-Methode.
Negativ zu werten wäre (ich bin immer noch beim Konjunktiv) dann auch der Umstand, dass Du die Reihenfolge beachten müsstest, mit der die beiden Doppelschleifen aufgerufen werden. Es müsste - wie Du selbst bereits erwähnt hast - zunächst die Amplitude und dann erst die Phase "gesetzt" werden, weil umgekehrt das Setzen der Phase sinnlos ist.
Das wäre jetzt alles nicht die Katastrophe - das ist auch nicht so viel Code, dass man gleich die Übersicht verlieren würde; aber wehre den Anfängen.
Wenn Du nur eine Doppelschleife hast, in der Du auf beide 2D-Arrays gleichzeitig zugreifst, so kannst Du aus einer Amplitude und einer Phase leicht eine komplexe Variable mit
std::complex< double > c = std::polar( amplitude, phase );
direkt erzeugen. Du benötigst kein einseitiges Set und Dein Code wäre im ganzen weniger und besser - immer alles vorausgesetzt, meine Glaskugel funktioniert.
Gruß
Werner
-
Werner Salomon schrieb:
Jester schrieb:
Warum sollte das ein Designfehler sein? Was ist schlimm daran, wenn ich eine Phasenverschiebung durchführen will? Oder nur die Amplitude ändern möchte? Ist ein sinnvoller Algorithmus, der das tun möchte wirklich unvorstellbar?
Es ist nicht schlimm, die Amplitude zu verändern, sondern es ist meistens ein Hinweis auf ein Problem woanders, wenn man sie neu Setzen möchte.
Warum? Ist es auch ein Hinweis auf ein Problem woanders, wenn ich eine int-variable neu setzen möchte? Wo liegt der qualitative Unterschied?
-
Jester schrieb:
Werner Salomon schrieb:
Jester schrieb:
Warum sollte das ein Designfehler sein? Was ist schlimm daran, wenn ich eine Phasenverschiebung durchführen will? Oder nur die Amplitude ändern möchte? Ist ein sinnvoller Algorithmus, der das tun möchte wirklich unvorstellbar?
Es ist nicht schlimm, die Amplitude zu verändern, sondern es ist meistens ein Hinweis auf ein Problem woanders, wenn man sie neu Setzen möchte.
Warum?
Weil - wie in diesem Fall - die komplexe Zahl eine physikalische Größe beschreibt. Und sowas ist normal nicht teilbar - das Feld kann an einer Stelle nicht nur eine Amplitude haben aber keine Phase. Wenn man schon die Größe in EINE Klasse unterbringt, dann deshalb, weil Real- und Imaginärwert bzw. Amplitude und Phase zusammengehören. Und wenn die (lokale) Anforderung aufkommt eines (und nur eines) von beiden neu setzen zu wollen, so sind oder waren an diesem Punkt Phase und Amplitude nicht mehr zusammen sondern getrennt. Und damit ist der Code zumindest an diesem Punkt schlecht strukturiert.
Jester schrieb:
Ist es auch ein Hinweis auf ein Problem woanders, wenn ich eine int-variable neu setzen möchte?
Nein, genauso wenig, wie es ein Problem sein muss, eine komplexe Zahl neu zu setzen. Wenn aber jemand danach fragt, wie man ein bestimmtes Bit eines int setzen kann und gleichzeitig versichert, dass dieses int im Grunde eine Anzahl oder einen Index beschreibt, so würde ich vermuten, dass da was faul ist.
Jester schrieb:
Wo liegt der qualitative Unterschied?
Der Unterschied liegt darin, ob man etwas ganzes manipuliert, was offensichtlich ganz ist, weil es ist Arbeit hineingeflossen, um es als Ganzes handel zu können - nämlich die Klasse ... oder ob man es wieder aufbricht und versucht bewusst nur einen Teil zu setzen. Das bricht die Kapselung, die die Klasse vorher aufgebaut hat und widerspricht der Idee der OOP.
Gruß
Werner
-
Werner Salomon schrieb:
Wenn Du nur eine Doppelschleife hast, in der Du auf beide 2D-Arrays gleichzeitig zugreifst, so kannst Du aus einer Amplitude und einer Phase leicht eine komplexe Variable mit
std::complex< double > c = std::polar( amplitude, phase );
direkt erzeugen. Du benötigst kein einseitiges Set und Dein Code wäre im ganzen weniger und besser - immer alles vorausgesetzt, meine Glaskugel funktioniert.
Wenn ich wirklich beides Setzen will, dann hast du Recht. Was ich aber in der Regel mache ist ein
std::complex< double > c = std::polar( abs(c), phase );
oder ein
std::complex< double > c = std::polar( amplitude, arg(c));
Das heißt ich habe ein Array von Complexen Zahlen in denen ich die Phase oder Amplitude aus einem anderen Array ändere.
Matthias
-
Was spricht dagegen, die Schnittstelle einer Klasse (std::complex) zu erweitern, indem man ihr eine Nicht-Memberfunktion spendiert (wie die, die ich oben gepostet habe und die genau das tut was hier gefragt ist, naemlich die Amplitude neu setzen)? Ein Klasseninterface besteht schliesslich nicht nur aus den Memberfunktionen der Klasse, und wenn man eine Funktion als Nicht-Member und Nicht-Friend implementieren kann, dann sollte man das auch tun. In diesem Fall bleibt dir sogar garnichts anderes übrig, da std::complex nunmal nicht zum Ableiten desgint wurde.
-
Mag sein, dass complex nicht zum Ableiten designed wurde, es sollte aber trotzdem möglich sein, solange man keine neuen Membervariablen hinzufügt. Das Problem ist doch der nichtvirtuelle Destruktor (bei meiner Dinkumware sogar nur ein default-Destruktor). Wenn man nur neue Funktionen hinzufügt sollte es trotzdem gehen.
-
Braunstein schrieb:
Mag sein, dass complex nicht zum Ableiten designed wurde, es sollte aber trotzdem möglich sein, solange man keine neuen Membervariablen hinzufügt. Das Problem ist doch der nichtvirtuelle Destruktor (bei meiner Dinkumware sogar nur ein default-Destruktor). Wenn man nur neue Funktionen hinzufügt sollte es trotzdem gehen.
Wenn Du auf die Problematik des Löschens über einen Basisklassenzeiger anspielst: Selbst ohne neue Membervariablen kann doch der Destruktor der abgeleiteten Klasse etwas ausführen? Darüberhinaus glaube ich, dass das auch dann undefiniertes Verhalten erzeugen kann, wenn im Destruktor der abgeleiteten Klasse eigentlich nichts mehr gemacht werden müsste.
Aber man kann ja auch einfach darauf verzichten, Objekte der abgeleiteten Klasse über Zeiger auf std::complex ansprechen (oder spezieller: löschen) zu wollen, dann ergibt sich die Problematik garnicht. Man könnte sogar verhindern, dass jemand einen Zeiger auf ein Objekt der abgeleiteten Klasse in einen Basisklassenzeiger umwandelt, indem man privat vererbt und die ganzen public-Funktionen über using verfügbar macht (ist allerdings nicht gerade elegant).
-
Genau.
Es stimmt schon, dass das nicht sonderlich schön ist. Ich würde es ehrlich gesagt auch nicht machen. In solchen Fällen würde ich einen Wrapper um complex herum schreiben. So viele Memberfunktionen sind es ja nicht. Die vielen Nichtmemberfunktionen könnte man ja über einen Konvertierungsoperator zufrieden stellen. Auch nicht schön, aber möglich.
-
Nochmal: Wozu sich die ganze zusätzliche Arbeit machen mit
- Ableiten, dokumentieren und hoffen, dass niemand das Derivat über einen pointer auf std::complex löscht, oder
- Wrapperklasse schreiben, die alles weiterleitet und nur Funktionalität hinzufügt die keinen Zugriff auf die Innereien der Klasse braucht
wenn man einfach einen Nonmemberfunktion definieren kann die genau das Gewünschte macht? Ob man jetzt
supercomplex<double> sc; sc.SetAmplitude(x);
schreib oder
std::complex<double> sc; SetAmplitude(sc, x);
macht rein leserlich keinen großen Unterschied, performancetechnisch überhaupt keinen.
Entgegen einiger Ansichten heißt Objektorientiertes Design eben nicht, dass man alles irgendwo ableiten muss und dass jede Operation als Methode irgendeiner Klasse deklariert sein muss.
-
Werner Salomon schrieb:
Weil - wie in diesem Fall - die komplexe Zahl eine physikalische Größe beschreibt. Und sowas ist normal nicht teilbar - das Feld kann an einer Stelle nicht nur eine Amplitude haben aber keine Phase.
In der Tat, trotzdem können sich beide unabhängig voneinander verändern. Und ich sehe auch nicht was daran merkwürdig sein sollte. Phasenverschiebung bei gleichbleibender Amplitude ist doch schon ein sinnvolles Beispiel.
Ich verstehe wirklich nicht wo du da nun unbedingt einen Designfehler finden willst (und vor allem warum).