Schrittweite bei floating point austüfteln ???


  • Mod

    Ich meinte die Vorgehensweise:

    1. Zwei exakt darstellbare Zahlen nehmen
    2. Differenz dieser beiden durch eine Zweierpotenz teilen
    3. Iteratives Addieren der Differenz auf den kleineren Wert
    4. Exaktes Ankommen beim größeren Wert.

    Aber: Jetzt, wo ich diese Vorgehensweise aufschreibe, fallen mir lauter Sonderfälle ein, wo das Verfahren scheitern wird. Beispielsweise wenn in Schritt 2 die Zweierpotenz zu groß ist, dann kommt in Schritt 3 Unsinn heraus. Insofern: Jetzt bin ich 100% sicher, dass das Verfahren doch nicht allgemein anwendbar ist. Aber es war natürlich umgekehrt auch kein Zufall, dass mein obiges Vorgehen für nicht zu extreme Werte zum Erfolg geführt hat.



  • Das es geht ist schon eher der Sonderfall. Bei alles float oder alles double, geht es fast nie. Wenn start, ende, schrittweite floats sind und die Zählvariable double, geht es dann, wenn die Exponenten der Zahlen nicht zu weit auseinanderliegen im Vergleich zu den Nullen am Ende in der Mantisse ( jeder float endet als double mit 30(?) Nullen. Das ist aber auch nur eine Faustregel. Im Prinzip wird beim Iterieren die Mantisse geschiftet während die Exponenten aufeinander zulaufen. Werden dabei hinten Daten rausgeschiftet für ein Zwischenergebnis, kommt man nicht beim korrekten Wert an.



  • @TGGC sagte in Schrittweite bei floating point austüfteln ???:

    Nicht wirklich.

    doch schon. es hat mir gezeigt dass meine idee mit floats zu zählen eine totale schnapsidee war. 🙂


  • Mod

    @TGGC sagte in Schrittweite bei floating point austüfteln ???:

    Das es geht ist schon eher der Sonderfall. Bei alles float oder alles double, geht es fast nie. Wenn start, ende, schrittweite floats sind und die Zählvariable double, geht es dann, wenn die Exponenten der Zahlen nicht zu weit auseinanderliegen im Vergleich zu den Nullen am Ende in der Mantisse ( jeder float endet als double mit 30(?) Nullen. Das ist aber auch nur eine Faustregel. Im Prinzip wird beim Iterieren die Mantisse geschiftet während die Exponenten aufeinander zulaufen. Werden dabei hinten Daten rausgeschiftet für ein Zwischenergebnis, kommt man nicht beim korrekten Wert an.

    Der Fall hier, wo alles ungefähr die gleiche Größenordnung hat, mag ja technisch gesehen der Sonderfall sein, wenn man zufällige Werte aus dem gesamten Wertebereich einer Fließkommazahl heran zieht, aber für "normale" Beispiele, wie sie sich ein Mensch ausdenken würde (z.B. dieses), geht es.



  • Nie verkehrt, auch mal weniger ausgetretene Pfade zu erkunden. Der Brot-und-Butter-Integer-Lerp ist hier zwar besser, dafür wird man aber auch seltener Namensgeber eines innovativen neuen Algorithmus, wenn man immer nur solche Standardlösungen rezitiert - auch wenn das in so abgegrasten Feldern eher selten vorkommt 😉

    Dennoch besser, das etwas deutlicher als "experimentell" zu markieren, wenn auch Neulinge mitlesen (vor allem diese Abbruchbedingung) 😉



  • @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    was auch noch ginge ist mit integer von -314 bis +314 zählen, mit schrittweite von 10, dann nach float casten und durch 100.0 teilen.
    das ist mir kurz danach eingfallen nachdem ich die frage stellte. immer erst ne minute nachdenken bevor man fragt. aber so hattet ihr auch euren spaß. 🙂
    und ich habe mich als noob geoutet.

    Wie soll das gehen?

    -314
    -304
    ...
    -  4
    +  6
    ...
    +306
    +316
    

    Punktlandung ist das keine.



  • Was du machen kannst:
    Zähl i von 0 bis 39564 in Schritten von 628. Dein Wert bei jedem Durchlauf ist dann x = (i - 19782) / 6300.0.

    Das sind dann genau 63 Schritte, wobei jeder Schritt 628/6300=0,099682539682539... ist.

    Ansonsten sollte auch diese wesentlich einfachere Variante genau genug für die allermeisten Anwendungen sein:

    #include <iostream>
     
    int main() {
        double const pi = 3.14; // oder auch gern genauer
        double const step = 2.0 * pi / 60.0;
        double const start = -pi;
        for (int i = 0; i <= 60; i++) {
            double const x = start + step * i;
            std::cout << x << "\n";
        }
    }
    

    https://ideone.com/jLQc2Z



  • @hustbaer sagte in Schrittweite bei floating point austüfteln ???:

    @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    was auch noch ginge ist mit integer von -314 bis +314 zählen, mit schrittweite von 10, dann nach float casten und durch 100.0 teilen.
    das ist mir kurz danach eingfallen nachdem ich die frage stellte. immer erst ne minute nachdenken bevor man fragt. aber so hattet ihr auch euren spaß. 🙂
    und ich habe mich als noob geoutet.

    Wie soll das gehen?

    -314
    -304
    ...
    -  4
    +  6
    ...
    +306
    +316
    

    Punktlandung ist das keine.

    mit der angepassten schrittweite. 2*314, d.h 628 hat 4 als teiler, also nimmt man 4 als schrittweite. das macht 157 werte.
    dann landet man wieder auf'm punkt.
    sind das zu viele dann schmeißt man jeden zweiten raus. hauptsache der erste und letzte beiben erhalten.
    es geht um das plotten von kurven auf einem kleinen display. diese kurven haben alle eine wellenlänge von 2 pi.



  • @hustbaer sagte in Schrittweite bei floating point austüfteln ???:

    double const pi = 3.14; // oder auch gern genauer
    double const step = 2.0 * pi / 60.0;
    double const start = -pi;
    for (int i = 0; i <= 60; i++) {
    double const x = start + step * i;
    std::cout << x << "\n";
    }

    das gefällt mir sehr.


  • Mod

    @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    es geht um das plotten von kurven auf einem kleinen display. diese kurven haben alle eine wellenlänge von 2 pi.

    Moment mal. Das passt aber gar nicht zu deiner Frage. Wenn mit endlichen Pixeln plottest, kannst du schließlich nicht die Schritte wählen, wie es dir passt, sondern du musst ausrechnen, welchen x-Wert jeder Pixel repräsentiert.



  • @SeppJ sagte in Schrittweite bei floating point austüfteln ???:

    @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    es geht um das plotten von kurven auf einem kleinen display. diese kurven haben alle eine wellenlänge von 2 pi.

    Moment mal. Das passt aber gar nicht zu deiner Frage. Wenn mit endlichen Pixeln plottest, kannst du schließlich nicht die Schritte wählen, wie es dir passt, sondern du musst ausrechnen, welchen x-Wert jeder Pixel repräsentiert.

    das display ist 200 pixel breit. ein paar buttons sollen auch noch drauf.


  • Mod

    @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    @SeppJ sagte in Schrittweite bei floating point austüfteln ???:

    @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    es geht um das plotten von kurven auf einem kleinen display. diese kurven haben alle eine wellenlänge von 2 pi.

    Moment mal. Das passt aber gar nicht zu deiner Frage. Wenn mit endlichen Pixeln plottest, kannst du schließlich nicht die Schritte wählen, wie es dir passt, sondern du musst ausrechnen, welchen x-Wert jeder Pixel repräsentiert.

    das display ist 200 pixel breit. ein paar buttons sollen auch noch drauf.

    Und? Ich glaube, du verstehst meinen Einwand nicht. Du gehst dein Problem verkehrt herum an und hast genau die falsche Frage gestellt.



  • @SeppJ sagte in Schrittweite bei floating point austüfteln ???:

    @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    @SeppJ sagte in Schrittweite bei floating point austüfteln ???:

    @Bushmaster sagte in Schrittweite bei floating point austüfteln ???:

    es geht um das plotten von kurven auf einem kleinen display. diese kurven haben alle eine wellenlänge von 2 pi.

    Moment mal. Das passt aber gar nicht zu deiner Frage. Wenn mit endlichen Pixeln plottest, kannst du schließlich nicht die Schritte wählen, wie es dir passt, sondern du musst ausrechnen, welchen x-Wert jeder Pixel repräsentiert.

    das display ist 200 pixel breit. ein paar buttons sollen auch noch drauf.

    Und? Ich glaube, du verstehst meinen Einwand nicht. Du gehst dein Problem verkehrt herum an und hast genau die falsche Frage gestellt.

    ja, die frage war totaler mist.



  • @TGGC sagte in Schrittweite bei floating point austüfteln ???:

    Nie mit float zählen, wenn es irgendwie nachvollziehbares Ergebnis sein soll. Zähle mit einem int die Anzahl der Schritte die du haben willst (z.b. 6.3/0.1 = 63) und lerpe mit i/(max -1) zwischen den Werten.

    Bitte nimm genau diese Lösung und nimm als Schrittzahl die gewünschte Anzahl Pixel.



  • @TGGC ja, genau so.

    Man sollte vielleicht noch erwähnen, dass man so eventuell Löcher im Kurvenplot erhält, wenn man einfach nur die Pixel an den ausgerechneten (x, y)-Koordinaten setzt.

    Das passiert z.B., wenn die Kurve in y-Richtung schneller ist als in x-Richtung (z.B. zwei Pixel nach oben für einen Pixel nach rechts).

    Simple Lösung ist keine einzelnen Pixel zu zeichnen, sondern stattdessen gerade Linien zwischen einem Kurvenpixel und seinem Vorgänger. Da kann einem da z.B. der gute alte Jack Bresenham weiterhelfen. Den Algo sollte man ohnehin irgendwo am Start haben, wenn man das Display schon pixelweise selbst programmieren muss 😉


  • Mod

    Darauf kommt Kollege Bushmaster hoffentlich auch, spätestens wenn er den ersten Plot sieht. Interessanter ist aber das Problem, dass man bei einer geringen Auflösung leicht einen Sampling-Error bekommen kann. Mit 200 Punkten erfasst man evtl. gar nicht die Extrempunkte, die für die Characterisierung wichtig sind, sondern zeichnet eine völlig andere Kurve.

    Wenn er was von 2π-Periode schreibt, sind das wahrscheinlich irgendwelche Schwingungen, die er darstellen möchte. Da ist das Problem oft sogar besonders verstärkt, weil man dann irgendwelche Muster bekommt, die gar nichts mit der Realität zu tun haben, aber bedeutsam aussehen.

    So weit ich weiß ignorieren viele Plotprogramme das Problem (ist halt auch nicht so einfach zu lösen), aber gerade bei geringen Auflösungen ist es relevanter.



  • @SeppJ sagte in Schrittweite bei floating point austüfteln ???:

    Wenn er was von 2π-Periode schreibt, sind das wahrscheinlich irgendwelche Schwingungen, die er darstellen möchte. Da ist das Problem oft sogar besonders verstärkt, weil man dann irgendwelche Muster bekommt, die gar nichts mit der Realität zu tun haben, aber bedeutsam aussehen.

    Zumindest Aliasing-Artefakte lassen sich nach Nyquist–Shannon vermieden, wenn man sicherstellt, dass in jeder Periode mindestens 2 Abtastpunkte liegen. Dann hat man zumindest keine Frequenzen in der Abbildung, die da nicht reingehören. Die Amplituden können aber dennoch etwas komisch sein, je nachdem, welche Punkte man erwischt. Schön wäre z.B. bei der Sinusfunktion zumindest die Extremwerte mit +1/-1 voll drin zu haben.

    So weit ich weiß ignorieren viele Plotprogramme das Problem (ist halt auch nicht so einfach zu lösen), aber gerade bei geringen Auflösungen ist es relevanter.

    Man möge mich korrigieren, aber ich glaube das lässt sich effektiv nur lösen, indem man den Plot in (für die darin enthaltenen Frequenzen) ausreichend hoher Auflösung im Speicher zeichnet und das dan auf die Display-Auflösung heruntersampelt (hochaufgelöstes Bild z.B. mit Gauss-Filter bandbegrenzen und dann auf Ziel-Auflösung herunterskalieren [Supersampling]).

    Das wird aber schnell aufwändig, und ist für die Anforderungen von @Bushmaster sicher erstmal Overkill 😉


  • Mod

    @Finnegan sagte in Schrittweite bei floating point austüfteln ???:

    @SeppJ sagte in Schrittweite bei floating point austüfteln ???:

    Wenn er was von 2π-Periode schreibt, sind das wahrscheinlich irgendwelche Schwingungen, die er darstellen möchte. Da ist das Problem oft sogar besonders verstärkt, weil man dann irgendwelche Muster bekommt, die gar nichts mit der Realität zu tun haben, aber bedeutsam aussehen.

    Zumindest Aliasing-Artefakte lassen sich nach Nyquist–Shannon vermieden, wenn man sicherstellt, dass in jeder Periode mindestens 2 Abtastpunkte liegen. Dann hat man zumindest keine Frequenzen in der Abbildung, die da nicht reingehören. Die Amplituden können aber dennoch etwas komisch sein, je nachdem, welche Punkte man erwischt. Schön wäre z.B. bei der Sinusfunktion zumindest die Extremwerte mit +1/-1 voll drin zu haben.

    Jupp. Aber das weiß ja das allgemeine Plotprogramm nicht 🙂
    Und wie du selbst sagst, ist das höchstens ausreichend, damit ein Computer ein Signal (innerhalb gewisser Schranken) rekonstruieren kann, aber das heißt noch nicht, dass es gut aussieht. Ich weiß auch keine tolle Lösung. Habe so einiges gesehen, was mal mehr oder weniger gut geht. Ich würde es auch erst einmal ignorieren, aber unbedingt daran denken, sobald die erste Kurve komisch aussieht.



  • @Finnegan Ich glaube eine häufige Variante ist es in jeder Pixelspalte eine vertikale Linie von min bis max der von dieser Pixelspalte abgedeckten Samples zu machen. Dadurch bekommst du dann einen fliessenden Übergang zwischen "Waveform" und dieser Darstellung mit den Knubbeln/dem dicker und dünner werdenden Balken bzw. wie auch immer man es nennen möchte.



  • Das Nyquist–Shannon Theorem bringt hier grad mal null. Wenn man einfach nur die Punkte zeichnet bzw. die dann noch linear interpoliert, fügt man nämlich noch neue Frequenzen hinzu (man hat dann Rechteck/Sägezahnwellen). Das Theorem sagt lediglich aus, das es nur eine einzige Funktion gibt, die man aus kleineren Frequenzen bauen kann, die dann genau durch alle Punkte geht. Und die Visualisierung zeigt eben nicht diese Funktion.


Anmelden zum Antworten