sin/cos in/um atan2 anders ausdruecken/optimieren?



  • Ich habs mal Online-Kompilieren/Rechnen lassen mit diesem Code

    http://cpp.sh/46hsr

    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
        double c = 22.33;
        double sin_c = sin(c);
        double cos_c = cos(c);
        double v = atan2(cos_c, sin_c)/2.0;
        double sin_v = sin(v);
        double cos_v = cos(v);
        double sin_v2 = sin(c/2.0);
        double cos_v2 = cos(c/2.0);
        printf("sin_v: %.3f, cos_v: %.3f, sin_v2: %.3f, cos_v2: %.3f\n", sin_v, cos_v, sin_v2, cos_v2);
    }
    

    Ergebnis: sin_v: -0.816, cos_v: 0.578, sin_v2: -0.986, cos_v2: 0.169



  • du hast bei der atan2 x und y vertauscht. sinus alpha ergibt y und cosinus alpha ergibt x.
    wenn du atan2(sin_c,cos_c) aufrufst gehts. http://cpp.sh/44ccw



  • du hast bei der atan2 x und y vertauscht.

    mein y ist aber cos(c) und x ist sin(c) - das kann ich nicht so einfach aendern sonst kommen bei der Berechung voellig andere Werte raus



  • also ich weiß ja nicht, was du da jetzt genau berechnen willst, aber

    tangens x ist sinus x/cosinus x. wenn du davon dann den arkustangens nimmst, hast du wieder x und wenn du das ganze durch 2 teilst, hast du x/2 und deshalb macht es (mathematisch) keinen unterschied, ob du cos(arctan(sin(x)/cos(x))/2) oder cos(x/2) rechnest.

    und bei gängigen kartesischen koordinatensystemen gibt der sinus die höhe des dreiecks 👍 und der cosinus die breite (x) an, weshalb du entweder atan2 falsch aufrufst, oder irgendetwas berechnen willst, dass so nicht funktioniert.



  • Wade1234 schrieb:

    tangens x ist sinus x/cosinus x. wenn du davon dann den arkustangens nimmst, hast du wieder x und wenn du das ganze durch 2 teilst, hast du x/2 und deshalb macht es (mathematisch) keinen unterschied, ob du cos(arctan(sin(x)/cos(x))/2) oder cos(x/2) rechnest.

    Und wenn er Sinus und Cosinus vertauscht, ergibt arctan den Gegenwinkel (bzw. dessen Bogenmaß bis auf Vorzeichen). Mithin

    double v2 = (M_PI/2 - c)/2;
    


  • und bei gängigen kartesischen koordinatensystemen gibt der sinus die höhe des dreiecks 👍 und der cosinus die breite (x) an, weshalb du entweder atan2 falsch aufrufst, oder irgendetwas berechnen willst, dass so nicht funktioniert.

    ich habe eine seit 10 Jahren im (Dauer)Einsatz befindliche (2 Glieder)5-Achs-Kinematik-Brechnung durch Mathematica Simplify usw gejagt und das ganze ca. um Faktor 20 beschleunigt - als Test läuft der optimierte Code parallel zum Original und durchläuft alle statischen und fixen Testcases die ich finden konnte, nebst Daten die eine Voll-Abdeckung des alten Berechungs-Codes verursachen - dahingehend würde ich mal vorsichtig behaupten meine Optimierung arbeitet wenigstens korrekt - die Sin/Cos sind Ergebnisse für einen Quaternian mit dem ich dann viel weiter rotieren



  • double v2 = (M_PI/2 - c)/2;

    Danke camper sieht schon mal ein wenig besser aus

    http://cpp.sh/6tbio

    kann man die Vorzeichnen noch angleichen - die sin(v2) und cos(v2) gehen nur
    noch multiplikativ ein - da ist das Vorzeichen wichtig 🙂



  • kann man die Vorzeichnen noch angleichen

    wird wohl schwer ohne atan2



  • sorry für die blöde frage, aber was willst du da eigentlich genau berechnen?



  • sorry für die blöde frage, aber was willst du da eigentlich genau berechnen?

    den Kontaktpunkt einer 2-Glider 5-Achs-Kinematik - ich habe aber bisher nur geprüft wie weit sich die Berechnungen aus dem Original-Code reduzieren lassen (bei 100% gleichen Daten zum Original)
    im wesentlichen sind das jetzt sin/cos von 2 Achsen und atan2 darauf - von dem m
    athematischen Zusammenhang erkennt man jetzt aber glaube ich nicht mehr viel

    meine letzte Idee war es jetzt noch den sin und cos von atan2(cos(c),sin(c))/2.0 auszuspezialisieren - dann werden alle weiteren sin/cos durch ein paar sqrts(die scheinbar weniger Power brauchen) ersetzt - bringt nochmal fast 5 sek bei 70Mio Durchläufen 🙂



  • Gast3 schrieb:

    double v2 = (M_PI/2 - c)/2;

    Danke camper sieht schon mal ein wenig besser aus

    http://cpp.sh/6tbio

    kann man die Vorzeichnen noch angleichen - die sin(v2) und cos(v2) gehen nur
    noch multiplikativ ein - da ist das Vorzeichen wichtig 🙂

    Die Vorzeichen sind entweder beide richtig oder beide falsch. Was letztlich damit zu tun hat, dass deine sin_v(c) und cos_v(c) keine richtigen sinus/cosinus-Funktionen sind.
    Wenns drauf ankommt, muss man eben beachten, in welchem Quadranten c liegt:

    double v2 = remainder(M_PI / 2 - c, 2 * M_PI) / 2;
    

  • Mod

    Versuch doch mal von den Mathematica-Umformungen weg zu kommen (die wahrscheinlich nicht funktionieren, da du wahrscheinlich mit komplexen Zahlen rechnest) und denk darüber nach, was die Formel tun soll. Denkst du, ich hätte für meine Antwort gerechnet und umgeformt? Ich habe nur gesehen, dass die Kombination sin, cos einen Winkel in ein Koordinatenpaar umwandelt, atan2 ein Koordinatenpaar zurück in einen Winkel umwandelt und du dann einfach nur wieder sin und cos von dem halben Winkel nimmst, man sich die ganze Umformerei auch hätte sparen können. Das ganze Geplänkel danach, wo du sin und cos vertauscht und/oder Minuszeichen einführst geht doch nur noch darum, wie genau du deine Winkel definierst. Also denk mal darüber nach, welchen Winkel genau du hier aus welchen Gründen halbieren möchtest, dann hast du deine Lösung sofort.



  • Versuch doch mal von den Mathematica-Umformungen weg zu kommen (die wahrscheinlich nicht funktionieren, da du wahrscheinlich mit komplexen Zahlen rechnest) und denk darüber nach, was die Formel tun soll.

    ich hab auch schon langsam gemerkt das Mathematica und Konsorten keine Wunder vollbringen - bisher habe ich es einfach vermieden mich tiefer einzuarbeiten - ist nur ein On-Off Projekt von mir und normalerweise mache ich gar nichts mit Mathe - oder ist 10 Jahre her das ich mal was gemacht habe - d.h. ich muss mich in jedes Detail wieder reinarbeiten - aber ihr öffnet mir gerade die Augen



  • Danke camper - nochmal 5sek 🙂

    jetzt bleiben noch 2 Dinge:

    kann man hier noch weiter reduzieren (ich suche gerade nach der remainder Implementierung)

    double v = remainder(M_PI / 2 - c, 2 * M_PI) / 2;
    double cos_v = cos(v);
    double sin_v = sin(v);
    

    mein nächstes Privat-Projekt - anständig in Trigonometrie einarbeiten und eure Punkte hier nachvollziehen



  • remainder macht Divison und rundet u.a. - da kann ich wohl nichts rausziehen


  • Mod

    Viele Rechnenwerke können Sinus und Cosinus gemeinsam berechnen. Da besteht noch Handoptimierungspotential, sofern dein Compiler diese Optimierung nicht schafft.



  • c kann jeder beliebige Winkel sein, also
    c = φ + n * 2π ; -π <= φ < π; n ganz
    Der halbe Winkel v muss dagegen im Bereich -π/2 <= v < π/2 liegen. Das n stört hier und und remainder entfernt es.

    Ich weis ja nun nicht wo dein c herkommt. Evtl. kennst du ja den Faktor n bereits anderweitig (genaugenommen reicht es ja sogar zu wissen, ob es gerade ist oder nicht), das könnte z.B. vollständigen Umdrehungen in deiner Steuerung entsprechen. Wenn es bekannt ist, kannst du auch einfach entsprechend mit 2π multiplizieren und von c abziehen, und dafür auf remainder verzichten.



  • SeppJ schrieb:

    Viele Rechnenwerke können Sinus und Cosinus gemeinsam berechnen. Da besteht noch Handoptimierungspotential, sofern dein Compiler diese Optimierung nicht schafft.

    es gibt den alten x86 FPU FSINCOS - der ist aber sehr langsam verglichen mit den neueren SSE2(+) Implementationen, und der Microsoft-Kompiler fasst sin/cos nicht zusammen weil ja der 1. Aufruf errno setzen könnte - gcc ruft eine zusammengefasste routine auf, clang kann man da mit fast-math-sub-optionen nachhelfen

    https://godbolt.org/g/vh9dqT

    ich habe auch schon versuche mit boost.SIMD gemacht - war aber viel langsamer - werde da aber noch die Autor kontaktieren

    SeppJ schrieb:

    Ich weis ja nun nicht wo dein c herkommt.

    Das ist direkt eine Achsenposition - die kann alles von double min/max annehmen (nach meinem bisherigen Wissen)



  • ich verstehe auch überhaupt nicht warum diese Proposal zum hinzufuegen von std::sincos (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0081r0.pdf) in der Luft haengen geblieben ist - alle: egal ob Intel, Microsoft, clang, gcc, libc etc... jeder hat n Varianten (single/double/gpu/x86/x64(sse...)) - nur keine davon ist per Standard erreichbar

    oder dieser Hẹckmeck mit den math.h Routinen die errno setzen - und Optimierung verhindern - teilweise machen es die gcc-Routinen, manche nicht, clang hat wieder andere Builtins/Optimierungen - auf einer anderen Platform/Stdlib wieder total anders und, und, und

    ich hatte mal Kontakt mit einem der clang-cl Entwickler und der hat nur gemeint man soll den ganzen Müll in math.h mit komplett neuen Funktionen in einem neuen Namespace überlagern und die alten Zöpfe langsam abschneidbar machen
    - irgendwie stört sich niemand so richtig am dem Ist-Zustand - nur die Leute die damit kämpfen - und die sind scheinbar nicht laut genug



  • oder floating-Point(0) Optimierung nichts als #pragmas - sondern nur von aussen per --fast-math-optionen, kaum bis nichts bei Microsoft, einfach ein sehr unordentliches Süppchen da draussen


Anmelden zum Antworten