Definition von complex ?



  • 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

    1. Ableiten, dokumentieren und hoffen, dass niemand das Derivat über einen pointer auf std::complex löscht, oder
    2. 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).



  • Jester schrieb:

    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).

    Hallo Jester,

    warum und wieso meine ich schon ausreichend erläutert zu haben - inklusive Beispiel, welches Matthias, aber weder eindeutig dementiert noch bestätigt hat.
    Ich arbeite seit über 1o Jahren in einem Umfeld in denen solche Dinge wiederholt vorkommen. Bisher war es zu 95% so, dass z.B. eine SetX-Wert-Methode bei einer Position immer genau dann notwendig wurde, wenn ein Design-Problem in der Umgebung vorlag.

    pospiech schrieb:

    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.

    Hallo Matthias,

    wenn Du die Amplitude neu setzt, was ist dann mit der Phase, die bereis in 'c' ist - gehört sie zu der Amplitude, die da gerade gesetzt wird. Wenn ja - wo kommt sie in 'c' rein? Wenn nein - wo ist die Phase, die zu dieser Amplitude gehört - bzw. welchen Sinn macht dann ein komplexer Wert bei dem Phase und Amplitude nicht zusammen gehören?
    Befinden sich in dem anderen Array nur Werte für Amplituden bzw. Werte für Phasen? Falls nein warum wird dann nur der eine oder andere Wert daraus gelesen?

    pumuckl schrieb:

    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.

    Hallo pumuckl,

    da stimme ich völlig mit Dir überein.

    Gruß an alle
    Werner



  • Werner Salomon schrieb:

    Ich arbeite seit über 1o Jahren in einem Umfeld in denen solche Dinge wiederholt vorkommen. Bisher war es zu 95% so, dass z.B. eine SetX-Wert-Methode bei einer Position immer genau dann notwendig wurde, wenn ein Design-Problem in der Umgebung vorlag.

    es geht hier aber nicht um x,y-werte sondern eben um was anderes und insbesondere nicht um eine Klasse, die eine dicke Abstraktion wegkapselt und daher solche low-level sachen nicht bieten sollte. Mathematisch ist es eine sinnvolle operation, wieso sollte es da plötzlich ein Fehler sein?

    die schreibweise, die mit abs den alten absolutwert rausholt und den mit polar wieder setzt ist doch nichts anderes als ein häßlicher kleiner hack um das für diesen Anwendungsfall ungeeignete interface von std::complex zu kaschieren. Eventuell wäre es sinnvoller eine eigene complex-klasse zu nutzen, die intern nicht imaginär- und realteil, sondern eben betrag und phase speichert. da ließe sich die operation bequem anbieten.



  • Hallo Jester,

    unsere Diskussion hier ist schon sehr mühselig .. 😉 nun gut.

    Jester schrieb:

    Werner Salomon schrieb:

    Ich arbeite seit über 1o Jahren in einem Umfeld in denen solche Dinge wiederholt vorkommen. Bisher war es zu 95% so, dass z.B. eine SetX-Wert-Methode bei einer Position immer genau dann notwendig wurde, wenn ein Design-Problem in der Umgebung vorlag.

    es geht hier aber nicht um x,y-werte sondern eben um was anderes

    Eine Position mit x und y eine komplexe Zahl mit Winkel und Betrag oder ein Geldbetrag mit Nennwert und Währung machen aus einer Informationstechnischer Sicht, bei der es darum geht, wie strukturiere ich mein Programm, erstmal keinen Unterschied.

    Man stelle sich vor, es gibt eine Klasse für einen Geldbetrag und plötzlich braucht jemand eine SetWährung-Methode - das kann doch nur ein Restaurant-Besitzer bei der DM-Euro-Umstellung gewesen sein. Und das war doch wohl auch ein 'Designfehler' - oder nicht?

    Jester schrieb:

    und insbesondere nicht um eine Klasse, die eine dicke Abstraktion wegkapselt

    genau wie bei einer Position

    Jester schrieb:

    Mathematisch ist es eine sinnvolle operation,

    da bin ich gänzlich anderer Meinung ..

    Jester schrieb:

    die schreibweise, die mit abs den alten absolutwert rausholt und den mit polar wieder setzt ist doch nichts anderes als ein häßlicher kleiner hack um das für diesen Anwendungsfall ungeeignete interface von std::complex zu kaschieren.

    Das meine ich auch, aber genau dass müßte doch eine Set-Amplitude-Methode tun, oder siehst Du eine andere Möglichkeit, wenn intern Real- und Imaginärteil abgelegt sind?

    Jester schrieb:

    Eventuell wäre es sinnvoller eine eigene complex-klasse zu nutzen, die intern nicht imaginär- und realteil, sondern eben betrag und phase speichert. da ließe sich die operation bequem anbieten.

    richtig - und wenn gleichzeitig SetRealAnteil verlangt wird - was dann?

    Gruß
    Werner



  • Werner Salomon schrieb:

    unsere Diskussion hier ist schon sehr mühselig .. 😉 nun gut.

    In der tat, da helfen offensichtlich auch 10 Jahre Berufserfahrung nicht. 😉

    Jester schrieb:

    Eine Position mit x und y eine komplexe Zahl mit Winkel und Betrag oder ein Geldbetrag mit Nennwert und Währung machen aus einer Informationstechnischer Sicht, bei der es darum geht, wie strukturiere ich mein Programm, erstmal keinen Unterschied.

    Aber hallo macht das einen Unterschied. Schließlich geht es um eine Design-Frage. Und wenn man etwas in Klassen verpackt, dann kommt es eben nicht mehr nur drauf an wie's dargestellt ist sondern eben auch auf das Verhalten und welche Operationen es anbietet.

    Man stelle sich vor, es gibt eine Klasse für einen Geldbetrag und plötzlich braucht jemand eine SetWährung-Methode - das kann doch nur ein Restaurant-Besitzer bei der DM-Euro-Umstellung gewesen sein. Und das war doch wohl auch ein 'Designfehler' - oder nicht?

    Nicht alles was hinkt ist ein Vergleich.

    Jester schrieb:

    und insbesondere nicht um eine Klasse, die eine dicke Abstraktion wegkapselt

    genau wie bei einer Position

    Genau, deswegen sollte die Position das auch bieten. Aber die umliegende Abstraktion, die auf der Position aufbaut sollte auf solche details natürlich keinen zugriff mehr bieten.

    Jester schrieb:

    Mathematisch ist es eine sinnvolle operation,

    da bin ich gänzlich anderer Meinung ..

    hihi. Also ist die Multiplikation mit e^(i*phi) mathematisch nicht sinnvoll? und wenn ich eine Implementierung haben möchte in der das keine multiplikation benötigt ist es ein designfehler?

    [quote="Jester"]
    Das meine ich auch, aber genau dass müßte doch eine Set-Amplitude-Methode tun, oder siehst Du eine andere Möglichkeit, wenn intern Real- und Imaginärteil abgelegt sind?

    Jester schrieb:

    Eventuell wäre es sinnvoller eine eigene complex-klasse zu nutzen, die intern nicht imaginär- und realteil, sondern eben betrag und phase speichert. da ließe sich die operation bequem anbieten.

    richtig - und wenn gleichzeitig SetRealAnteil verlangt wird - was dann?

    Tjo, wenn eben beides benötigt wird, dann wird eben beides benötigt. Dadurch wird es trotzdem nicht automatisch zum Designfehler.



  • Jester schrieb:

    Jester schrieb:

    Mathematisch ist es eine sinnvolle operation,

    da bin ich gänzlich anderer Meinung ..

    hihi. Also ist die Multiplikation mit e^(i*phi) mathematisch nicht sinnvoll? und wenn ich eine Implementierung haben möchte in der das keine multiplikation benötigt ist es ein designfehler?

    .. und ich habe die ganze Zeit geglaubt wir reden über die Set-Methoden SetAmplitude bzw. SetPhase. Und Du redest von der Multiplikation zweier komplexer Zahlen.

    Das erklärt die Verwirrung.



  • Werner Salomon schrieb:

    .. und ich habe die ganze Zeit geglaubt wir reden über die Set-Methoden SetAmplitude bzw. SetPhase. Und Du redest von der Multiplikation zweier komplexer Zahlen.

    Dir ist aber schon klar, dass die Multiplikation mit e^i*Phi gerade nur die Phase verändert, aber nicht die Amplitude? Man also mit Hilfe der geeigneten set-Funktion diese Operation direkt durchführen kann?



  • Jester schrieb:

    Werner Salomon schrieb:

    .. und ich habe die ganze Zeit geglaubt wir reden über die Set-Methoden SetAmplitude bzw. SetPhase. Und Du redest von der Multiplikation zweier komplexer Zahlen.

    Dir ist aber schon klar, dass die Multiplikation mit e^i*Phi gerade nur die Phase verändert, aber nicht die Amplitude?

    Ja sicher, weil der Betrag von e^i*Phi identisch 1 ist.

    Jester schrieb:

    Man also mit Hilfe der geeigneten set-Funktion diese Operation direkt durchführen kann?

    welche Operation meinst Du jetzt genau? Kannst Du bitte die von Dir erwähnte mathematische Operation

    Jester schrieb:

    Mathematisch ist es eine sinnvolle operation,

    mal als Formel hinschreiben und erklären, wie das in einer Methode SetPhase oder SetAmplitude eingeht.

    Ohne die bestehende Phase zu berücksichtigen, sehe ich da keine Chance. Und dann sind wir wieder hier:

    Jester schrieb:

    die schreibweise, die mit abs den alten absolutwert rausholt und den mit polar wieder setzt ist doch nichts anderes als ein häßlicher kleiner hack

    Gruß
    Werner


Anmelden zum Antworten