Möglichkeit cartesianAngle(Sin[c],-Cos[c]) weiter zu optimieren?
-
Ich probiere gerade eine Berechnung (in C/C++) zu optimieren - konnte schon sehr viel Optimieren - aber irgendwie denke ich das ich diese Funktion noch weiter "vereinfachen" kann
für Mathematica habe ich mal die relevante Funktion aus C/C++ portiert:
liefert: [ 0; 2 * pi ] ist allgemeine Routine
cartesianAngle[x_, y_] := Module[{}, If[x > 0 && y > 0, Atan[y/x], If[x < 0 && y > 0, Atan[-x/y]+Pi/2, If[x < 0 && y < 0, Atan[-x/y]+1.5*Pi, If[x == 0 && y > 0, Pi/2, If[x < 0 && y == 0, Pi, If[x == 0 && y < 0, 1.5*Pi, 0 ] ] ] ] ] ] ]
und davon brauche ich, durch meine Optimierung, nur diese Spezialisierung -
mit cartesianAngle x=Sin[aC], y=-Cos[aC], und vom -Ergebnis-Winkel wieder Sin und CosspecialTpDirectionCartensianAngleSincos[aC_] := Module[{}, angle = cartesianAngle[Sin[aC], -Cos[aC]]; { Sin[-angle], Cos[-angle] } ]
\left\{ \begin{array}{cc} \{ & \begin{array}{cc} -1 & \sin (c)=0\land \cos (c)<0 \\ 1\. & \sin (c)=0\land \cos (c)>0 \\ -\cos (\text{Atan}(\tan (c))) & \sin (c)<0\land \cos (c)<0 \\ -\sin (\text{Atan}(-\cot (c))) & \sin (c)>0\land \cos (c)<0 \\ -\sin (\text{Atan}(\tan (c))+4.71239) & \sin (c)<0\land \cos (c)>0 \\ \end{array} \\ \end{array} , \begin{array}{cc} \{ & \begin{array}{cc} -1 & \sin (c)<0\land \cos (c)=0 \\ -\text{1.8369701987210297$\grave{ }$*${}^{\wedge}$-16} & \sin (c)=0\land \cos (c)>0 \\ 1 & (\cos (c)=0\land \sin (c)\geq 0)\lor (\cos (c)>0\land \sin (c)>0) \\ \cos (\text{Atan}(-\cot (c))) & \sin (c)>0\land \cos (c)<0 \\ \cos (\text{Atan}(\tan (c))+4.71239) & \sin (c)<0\land \cos (c)>0 \\ -\sin (\text{Atan}(\tan (c))) & \sin (c)<0\land \cos (c)<0 \\ \end{array} \\ \end{array} \right\}Simplify[specialTpDirectionCartensianAngleSincos[c], Element[c, Reals]]
meine Hoffnung war die If/Else Party zu verkleinern
- ich koennte z.B. die Pi, Pi/2 usw. gleich durch die Konstanten ersetzenoder z.B. Atan[y/x] => Atan[-Cos[aC]/Sin[aC]] nur durch Sin, Cos und Sqrt ausdruecken - wenn das geht/was bringt
Mathematicas Simplify hat bisher sehr gut geholfen - aber jetzt gehen uns beiden die Ideen aus
-
Beschreib doch lieber, was du erreichen möchtest, anstatt eine unübersichtliche Formel hin zu klatschen.
Die Formel sieht sehr danach aus, als hätte jemand noch nie von atan2 gehört.
-
Es ist eine Art 5-Achsen Kinematik(Rotationen/Translationen) die ich versuche (erstmal ohne Einstieg in die Mathe dahinter) zu optimieren - ist ein Privat-Spaß, ich machen sonst 0 mit Mathe, und bin auch schon ein paar Jahre draußen, will einem Bekannten zeigen das in seinem Code ein ordentliches Optimierungspotential steckt - oder dass auch eine Abbildung in/Nutzung von Mathematica(und Konsorten) gewisse Vorteile bringen könnte - ich war doch relativ erstaunt wie gut Mathematica einem Laien wie mir da unter die Arme greift
bisher habe ich die fixen 0 oder 1 Anteile (in z.B. Richtungs-Vektoren) in den Berechnungen optimiert und z.B. sich ergebende sin(x)2+cos(x)2 usw aufgelöst (nach dem ich den Trial gefunden hatte von Mathematica entfernen lassen) - dabei fällt das ganze ziemlich stark zusammen - und wird dabei auch ordentlich schneller, also schon mal mein kleines Ziel ("sieht du, da geht was") erreicht - die Algorithmen reduzieren sich auf triviale sin,cos,+,- Operationen
am Ende wird dann diese cartensian_angle Routinen benutzt (was die genau macht ist mir noch nicht so klar) die nach meiner "Optimierung" eben nur noch Sin(c),-Cos(c) als Eingangs-Parameter bekommt und ich hatte gedacht dort auch noch ohne größeren Aufwand(Einarbeitung) etwas verbessern zu können - also habe ich nachdem ich dann mal verstanden habe wie man in Mathematica Funktionen definiert die da durch gejagt aber das Ergebnis war lange nicht so erfreulich wie bei den anderen Schritten
Die Formel sieht sehr danach aus, als hätte jemand noch nie von atan2 gehört.
die cartesianAngle wurde bestimmt vor vielen Jahren aus einem Buch, einer Lib oder dem Internet kopiert
wenn ich das also richtig verstanden habe könnte man die cartesianAngle-Routine auch mit atan2 implementieren - muss dann wohl doch tiefer rein als ich eigentlich vor hatte
-
also kurz:
hat hier jemand eine atan2 Varianten von folgender Funktion?
cartesianAngle[x_, y_] := Module[{}, If[x > 0 && y > 0, Atan[y/x], If[x < 0 && y > 0, Atan[-x/y]+Pi/2, If[x < 0 && y < 0, Atan[-x/y]+3*Pi/2, If[x == 0 && y > 0, Pi/2, If[x < 0 && y == 0, Pi, If[x == 0 && y < 0, 3*Pi/2, 0 ] ] ] ] ] ] ]
und noch in Schön
Simplify[cartesianAngle[x, y], Element[c, Reals]]
sonst probiere ich mich selbst drann
-
Wenn ich das richtig sehe ist das eben die atan2 Funktion. Nur selbst nachgebaut.
Wenn aus cartesischen Koordinaten der Winkel am Ursprung zwischen der Linie vom Ursprung zum durch von (x,y) gegebenen Punkt berechnet werden soll, nimmt man dafür üblicherweise den atan(y/x). Der atan hat aber das Problem, den Winkel eben nicht in jedem Quartal des Koordinatenkreuzes richtig darstellen zu können. Daher nimmt man hier den atan2(y, x) (oder man macht eine ewig lange Fallunterscheidung um das Ergebnis zu korrigieren).
Beachte, dass in den C und C++ Implementationen erst der y-Parameter und dann der x-Parameter übergeben wird.
-
hab mal ein bisschen mit C++ und Mathematica gespielt
hab noch einen Fehler in meiner cartesian_angle-Portierung fuer Mathematica gefunden
so sieht sie jetzt aus
cartesianAngle[x_, y_] := Module[{}, If[ x > 0 && y > 0, Atan[ y / x ], If[ x < 0 && y > 0, Atan[ -x / y ] + Pi/2, If[ x < 0 && y < 0, Atan[ y / x ] + Pi, If[ x > 0 && y < 0, Atan[ -x / y ] + 3*Pi/2, If[ x == 0 && y > 0, Pi/2, If[ x < 0 && y == 0, Pi, If[ x == 0 && y < 0, 3*Pi/2, 0 ] ] ] ] ] ] ] ]
hab mal in C++ die std::atan2 probiert:
( x, y) ( 1, 1) c++-cartesian_angle: 0.785398 std::atan2: 0.785398 equal: 1 (-1, 1) c++-cartesian_angle: 2.356194 std::atan2: 2.356194 equal: 1 (-1,-1) c++-cartesian_angle: 3.926991 std::atan2: -2.356194 equal: 0 !!! ( 1,-1) c++-cartesian_angle: 5.497787 std::atan2: -0.785398 equal: 0 !!! ( 0, 1) c++-cartesian_angle: 1.570796 std::atan2: 1.570796 equal: 1 (-1, 0) c++-cartesian_angle: 3.141593 std::atan2: 3.141593 equal: 1 ( 0,-1) c++-cartesian_angle: 4.712389 std::atan2: -1.570796 equal: 0 !!! ( 0, 0) c++-cartesian_angle: 0.000000 std::atan2: 0.000000 equal: 1
Geprüft:
1. die Mathematica-Funktions-Ausgabe mit den selben Punkten lierfert die gleichen Ergebnisse wie c++-cartesian_angle
2. die std::atan2 liefert bei manchen Punkten andere Ergebnisse als die c++-cartesian_angle
3. Mathematica ArcTan liefert für alle Punkte die gleiche Ergebnisse wie std::atan2die c++ cartesian_angle ist wohl doch keine 1:1 entsprechung zu atan2 - oder mache ich was anderes falsch?
-
Die Frage ist ob die C++-cartesian_angle vielleicht auch nicht richtig oder "äquivalent" implementierung zu atan2 ist
wenn ich atan2 Einsetzen könnte würde sich die specialTpDirectionCartensianAngleSincos auf {Cos[c], Sin[c]} reduzieren - was sehr schön wäre
-
Das sieht aus wie der entsprechende Gegenwinkel unter anderem Vorzeichen.
Die atan2 Funktion nimmt bei negativen y, den Winkel mit negativem Vorzeichen. Hast also einen Wertebereich von [-pi, pi]
Bei deiner cartesian_angle Implementierung nimmst du jeweils den positiven Winkel und hast den Wertebereich von [0, 2pi]
Bei folgendem Link findest du 'ne ganz nette Grafik, die den Wertebereich des atan2 wiedergibt: https://de.mathworks.com/help/fixedpoint/ref/atan2.html
-
Und bevor jetzt groß um den Unterschied herum gearbeitet wird: Wenn der Code zur Weiterverarbeitung des Ergebnisses etwas taugt, sollte es ihm egal sein, ob man 350 Grad oder -10 Grad sagt. Ist schließlich die gleiche Richtung, die man damit beschreibt.
-
Ich hab jetzt mal Testweise die cartesian_angle durch std::atan2 ersetzt und die Berechnung liefern immer noch identische Ergebnisse zum Original - auch die Reduzierung auf nur Cos[c],Sin[c] funktioniert - weniger geht nicht - noch mal 10-20sek schneller
Jetzt muss ich nur noch herausbekommen ob das anderer Verhalten von atan2 an den bestimmten Stellen problematisch sein kann
bisher vielen Danke für alle Tips
-
Lass mich raten: Der Winkel wird dann sowieso wieder in irgendwelche anderen trigonometrischen Funktionen eingesetzt. Falls ja, kann man sich das ganze Theater auch sparen und gewinnt ungeheuer viel Zeit.
Faustregel: Eine konkrete Winkelangabe ist etwas, das man praktisch niemals innerhalb einer Rechnung benötigt. Einen Winkel tatsächlich auszurechnen ist etwas, das man fast immer nur ganz am Ende macht, damit sich beispielsweise ein Mensch ein schönes Bildchen mit den Ergebnissen zeichnen möchte. Beim Numbercrunching selbst ist es (gewaltige!) Zeitverschwendung, Winkel zu berechnen.
-
Lass mich raten: Der Winkel wird dann sowieso wieder in irgendwelche anderen trigonometrischen Funktionen eingesetzt. Falls ja, kann man sich das ganze Theater auch sparen und gewinnt ungeheuer viel Zeit.
genau so ist es - es gehen als Parameter {sin(c),-cos(c)} in eine If-Orgie mit Atan,Cot und Tan usw. ein - und nach der Vereinfachung(durch atan2) kommt raus das das Ergebnis einfach immer {cos(c),sin(c)} ist - das hatte ich gehofft
jetzt ist nur noch eine (wieder sehr aehnliche) Rotations-Party übrig welche dieses {cos(c),sin(c)} nutzt - mal schauen ob das auch so zusammenfällt wie bei diesen Punkt hier
nochmals Danke
-
Nach meinem Gefühlt reduziert sich dadurch auch die Ungenauigkeiten - und wenn am Ende nur noch sin(c) und cos(c) übrig bleiben gibt es dafür bestimmt auch noch eine schöne SSE2/3/4... sincos, whatever Lösung - danach kann ich immer noch die Eingangsdaten mit n Threads durchkauen - aber eben erst mal schauen das Single-Threaded alles rausgeholt ist
-
Wie gesagt, die Lösung ist bestimmt eher beim Algorithmus für das Gesamtproblem bzw. der Mathematik zu suchen, als in der technischen Umsetzung dieses kleinen Abschnitts.
-
Wie gesagt, die Lösung ist bestimmt eher beim Algorithmus für das Gesamtproblem bzw. der Mathematik zu suchen, als in der technischen Umsetzung dieses kleinen Abschnitts.
Das ist mit klar - ich probiere das auch nur so weil der Algorithmus auch schon mit dieser Vorgehensweise ins fast nichts verdampft - und er auch nicht so gross ist
-
Mal aus Neugierde: Du hast geschrieben, dass es sich um eine 5 Achsen Kinematic handelt.
Meinst du damit tatsächlich, ein Glied, welches durch 5 Achsen angesteuert wird? Oder eine kinematische Kette mit 5 Gelenken?
Und geht es nur um die Vorwärts Kinematik, also die Bestimmung des Endpunktes, oder auch die Rückwärtskinematik?
Ich frage, weil ich mich damit selbst mal rumschlagen musste und mir damals zwischenzeitlich ganz schön einen abgebrochen habe
-
Meinst du damit tatsächlich, ein Glied, welches durch 5 Achsen angesteuert wird? Oder eine kinematische Kette mit 5 Gelenken?
es sind 2 Glieder mit 3 und 2 Achsen
Und geht es nur um die Vorwärts Kinematik, also die Bestimmung des Endpunktes, oder auch die Rückwärtskinematik?
nur Endpunkbestimmung