Schrittweite bei floating point austüfteln ???



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

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

    +/- 3.14 ist problematisch, da es im Binärsystem ein periodischer Bruch ist. Daher wirst du sowieso nie auf exakt 3.14 kommen. Nehmen wir einfache Genauigkeit an, sind die beiden nächsten exakten Werte +-/ 3.1400001049041748046875. Das ist ein Abstand von 6.280000209808349609375 (was dann naturgemäß auch wieder exakt binär darstellbar ist). Das geteilt durch 0.1 ist schön nahe an einer anderen Zweierpotenz, 64. Also teilen wir durch 64, das Ergebnis sollte dann auch wieder exakt in einen float passen: 0.098125003278255462646484375.
    Ausgezeichnet.

    Probieren wir es aus:
    https://ideone.com/MlodFf
    Arggh! Die Idee war gut, aber scheitert daran, dass da Zwischenergebnisse rauskommen, die nicht mehr exakte floats sind. Aber was, wenn wir die Genauigkeit der Zwischenergebnisse erhöhen? Ein bisschen geschummelt würden die einen sagen, ich nenne es einen Kunstgriff:
    https://ideone.com/eILuSC
    Punktlandung. Nice.

    danke, das hat geholfen.

    Nicht wirklich. Es erklärt nicht, warum die Zwischenergebnisse wieder keine exakten floats sind und in welchem Fall sie dann vlt. auch keine exakten doubles mehr sein würden. z.b. ist auch 1 ein exakter float und double, genau wie 2^n. Bis zu welchem n funktioniert aber ein for a = 1 to 2^n korrekt? Es gibt auch gar keine eindeutige Antwort darauf im C/C++ Universum.


  • Mod

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

    Nicht wirklich. Es erklärt nicht, warum die Zwischenergebnisse wieder keine exakten floats sind und in welchem Fall sie dann vlt. auch keine exakten doubles mehr sein würden. z.b. ist auch 1 ein exakter float und double, genau wie 2^n. Bis zu welchem n funktioniert aber ein for a = 1 to 2^n korrekt? Es gibt auch gar keine eindeutige Antwort darauf im C/C++ Universum.

    Also ich bin ca. 80% sicher, dass die von mir vorgestellte float-Methode immer funktionieren wird, wenn man die Zwischenergebnisse mit doppelter Genauigkeit speichert 🙂



  • @SeppJ Für die konkreten Werte? Und was ist funktionieren? Hält? Hält mit bestimmer Anzahl Iterationen? Alle Zwischenergbenisse identisch? Weil mit dem richtigen Endwert funktioniert ja auch die erste Variante, nur müsste man den eben erst in einer Schleife berechnen damit es "immer" funktioniert. Dann kann man in dieser Schleife auch schon die Arbeit machen.


  • 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 😉


Log in to reply