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



  • 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



  • hatte kurz Zugriff auf einen Dual Linux/Windows Rechner und einen sincos-Vergleich gemacht

    https://godbolt.org/g/uC9V2r

    Windows 7 x64, VS2017, x64/Release: 13,7 sek (kein sincos vorhanden)
    Standardsettings fuer Release

    Linux Ubuntu 17.04 x64, gcc 6.3, x64/Release: 10.4 sek (mit sincos per default)
    g++ -O2
    mit -march=native ist es langsamer geworden so 12.5 sek?



  • @camper:

    so jetzt bin ich mal wieder dazu gekommen alles zu testen

    dein tip mit remainder und atan2 hat für einen Fall wunderbar funktioniert

    double v_atan2 = atan2(cos_c, sin_c) / 2.0;
    double v_remainder = -remainder(c - M_PI / 2.0, M_PI * 2.0) / 2.0;
    

    aber für einen anderen Fall ist das Ergebnis nicht immer richtig

    double v_atan2 = atan2(-cos_c, -sin_c) / 2.0;
    double v_remainder = remainder(c - M_PI / 2.0, M_PI*2.0) / 2.0;
    

    cpp.sh/4fqsl

    kannst du mir nochmal erklären wie das mit dem reminder funktioniert damit
    ich das korrigieren kann



  • Gast3 schrieb:

    aber für einen anderen Fall ist das Ergebnis nicht immer richtig

    double v_atan2 = atan2(-cos_c, -sin_c) / 2.0;
    double v_remainder = remainder(c - M_PI / 2.0, M_PI*2.0) / 2.0;
    

    Deine Umformung ist inkorrekt. -cos_c und -sin_c entsteht, indem du c um π verschiebst.

    double v_remainder = remainder(-M_PI / 2.0 - c, M_PI*2.0) / 2.0;
    

    ist eine Möglichkeit.

    Bezgl.längerer Laufzeit mit -march=native (bzw. -mavx) ggf. https://www.c-plusplus.net/forum/344147 beachten.



  • Deine Umformung ist inkorrekt. -cos_c und -sin_c entsteht, indem du c um π verschiebst.

    Danke jetzt funktioniert es richtig - und ist auch gleich noch ein bisschen schneller geworden

    die Nutzung von remainder an dieser Stelle sollte auch die Präzision(weniger Rundungsfehler usw.) gegenüber atan2/sin/cos erhöhen oder sehe ich das falsch?

    sollte ich die Kinematik-Berechnung doch noch mal komplett frisch betrachten wird das eine oder andere aus den Diskussionen hier bestimmt mit einfliessen

    Danke



  • jetzt habe die ganze Kinematik noch mal durchgearbeitet und hab das ganze drastisch reduziert (kein If/Else, nur noch eine Rechnung)

    für mein gefordertes Ergebnis brauche ich jetzt nur noch:

    (
    x * sin(c) + y * cos(c),
    z * sin(a) - cos(a) * (x * cos(c) - y * sin(c)),
    x * sin(a) * cos(c) - y * sin(a) * sin(c) + z * cos(a)
    ) + offsets()

    einfacher geht wohl nicht mehr und hat die Berechnung nochmal um Faktor 2 beschleunigt

    jetzt sind die einzigen Zeitfresse sin und cos

    hat jemand vielleicht einen Tip ob es performantere Implementationen gibt
    die nicht total weit weg sind von der Präzision der Standardimplementationen?

    habe mir folgende angeschaut:

    http://gruntthepeon.free.fr/ssemath/ (original)
    https://github.com/RJVB/sse_mathfun (erweitert um SS3 und SSE4)
    eine abgewandelte Form von ssemath wird auch in Eigen verwendet:
    Eigen/src/Core/arch/SSE/MathFunctions.h
    Eigen/src/Core/arch/AVX/MathFunctions.h
    dann soll es noch was von Intel oder AMD geben

    btw: der x86 FSINCOS Befehl ist nicht schneller und nicht das was ich suche, nur eine SSE2+ Implementation kann da noch helfen - die eingebauten sin/cos sind schon SSE2+

    Erfahrungswerte?



  • und Boost.SIMD

    ssemath ist teilweise sehr ungenau und Boost.SIMD ist ein paar Sekunden langsamer



  • dann gibts es noch sincos Implementationen in

    Intel Integrated Performance Primitives (IPP)
    Intel Math Kernel Library (MKL)
    AMD Math Library (LibM)
    AMD Core Math Library (ACML)



  • ganz vergessen zu schreiben:

    die Sin+Cos Berechnungen brauche ca. 60-70% der Zeit (bei 70Mio Testläufen)


Anmelden zum Antworten