Rundungsfunktion FloatRound fehlerhaft

  • Die Rundungsfunktion FloatRound macht das, was sie soll, solange die Dezimalstellenzahl größer als Null ist. Soll ganzzahlig gerundet werden, dann werden die Nachkommastellen einfach abgeschnitten.

    Habe lange nach der Ursache für meine fehlerhaften Rechenergebnisse gesucht, weil ich natürlich dachte, dass meine eigenen Rechnungen fehlerhaft sind.

  • Emulator: DosBox unter W10

  • Da ich nur ganzzahlig runden will, behelfe ich mir so: Wenn die zu rundende Zahl positiv ist, addiere ich vor der Rundung 0.5, bei negativen subtrahiere ich 0.5. Das Abschneiden der Nachkommastellen führt so zur gewünschten Rundung.

  • Emulator: DosBox unter W10

    Das schweift zwar ab, aber ich hätte trotzdem eine Verständnisfrage zu diesem Code: Macht der überhaupt irgendwas?

    Die Variable zahl3, die von der Funktion zurückgegeben wird, wird ja nirgends (explizit) belegt.

    Oder passiert das alles indirekt?

    • FloatIEEE64ToGeos80() speichert zahl1 irgendwo
    • FloatRound() rundet zahl1 auf die mit zahl2 angegebene Zahl von Nachkommastellen
    • FloatGeos80ToIEEE64() fischt die gerundete zahl1 aus den nebulösen Speicheruntiefen heraus und gibt sie als zahl3 zurück

    Sieht so native Geos-Programmierung aus?

  • Hallo Sebi,

    Code
    bei der Benutzung des Borland-Compilers sah der Code verständlicher aus, weil durchweg mit dem FloatNum-Format gearbeitet werden konnte. 
    
    FloatNum round(FloatNum zahl1,byte zahl2)
    {
      FloatNum zahl3;
      FloatPushNumber(&zahl1);
      FloatRound(zahl2);
      FloatPopNumber(&zahl3);
      return(zahl3);
    } 

    FloatIEEE64ToGeos80(&zahl1) wandelt vom double- ins FloatNum-Format um und legt die Zahl auf den FP-Stack. FloatRound macht die Rundung und legt das Ergebnis auf dem Stack ab. FloatGeos80ToIEEE64(&zahl3) holt sich das Ergebnis und wandelt zurück ins double-Format. So die Kurzform:).

  • Hallo Wilfried,

    ich habe gerade Versuch das Problem nachzustellen. Ich sehe allerdings bei mir andere Ergebnisse:

    Ist die Emulation/das Target ein aktueller FreeGEOS-Built? Verwendest Du eine aktuelle Version von Staging DosBOX oder ein älteres Original?

    Viele Grüße,

    Falk \\ blueway.Softworks

  • Hallo Falk,

    interessant! Hast du in "Hello" die round-Funktion genau so definiert wie ich?

    Ich habe mir heute die aktuelle DosBox-Version (0.74-3) und die aktuelle Geos-Version heruntergeladen: Es zeigt sich keine Veränderung des beschriebenen Rundungsfehlers. Ob ich das neueste Target habe, weiß ich nicht. Meins ist vom Nov 24 (Syhra). Auch damit (Swat wird mitgestartet) zeigt sich der Fehler.

    Gruß

    Wilfried

  • Ich habe nun auch ein wenig mit dem geposteten Codeschnipsel experimentiert und auch in meinen Fällen wird durch round() das korrekte Ergebnis geliefert.

    Eine Idee wäre da noch: Die Funktionen FloatPushNumber(), FloatPopNumber() und FloatRound() delegieren an den Coprozessor, wenn ein solcher erkannt wird, dann wird zu jeder dieser Funktionen die korrespondieren x87 Instruktion aufgerufen. Falls kein Copro gefunden wird, dann werden diese Funktion durch x86 Instruktionen 'emuliert'. Vielleicht wird bei Wilfried der Copro nicht erkannt und die Emulation ist hier das Problem. Das ist aber nur Spekulation.

    Jirka

    Es ist auch dein FreeGEOS!

  • Hi,

    ich hab jetzt nicht mit dem Code gespielt, aber in R-BASIC nutze ich auch die Float~ Routinen, mit dem FP Stack und da wird auch richtig gerundet.

    Noch ne ganz dumme Idee - sowas in der Art hatte ich nämlich auch schon: Kann es sein, dass die Rechnung an sich korrekt ist, aber die Konvertierung in einen String schief geht? Ich weiß, dass ist unwahrscheinlich ...

    Rainer

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

  • So unwahrscheinlich ist das gar nicht…

    (s. Java, wo z.B. bei einem Zeitstempel mit Nanosekunden bei einem truncatedTo(ChronoUnit.MILLIS) mit anschließendem println trotzdem keine Millisekunden angezeigt werden, wenn die Uhrzeit nach dem Truncate genau 0 Millisekunden hat.)

    There are two rules in life:
    1. Never give out all of the information.

  • Vielen Dank für eure Hilfe!:)

    @Jirka: Wenn es so wäre wie du sagst, wie erklärst du dann, dass der Fehler nur bei Rundung auf 0 Dezimalstellen auftritt?

    Rainer: Tatsächlich tritt der Fehler in den Rechnungen auf. Bei Verschiebungen von Grafikobjekten traten immer Ungenauigkeiten auf, die ich mir nicht erklären konnte. Mit meinem Workaround sind sie weg.

    Wilfried

  • Gut, dann machen wir mal Nägel mit richtigen Köpfen. Im Anhang ein Programm, das bei mir funktioniert


    Mit im Archiv ist die compilierte Geode, die bei mir geht, sowohl unter BBX 4.13 als auch unter dem aktuellen Target

    Wilfried Was sagt die geode (aus dem Archiv, von mir compiliert) bei dir?
    Was passiert, wenn du das Ding selbst compilierts?

    Rainer

  • Rainer, deine Geode zeigt auch bei mir die richtigen Rundungswerte (auch nach Neucompilierung).:)

    Ich benutze seit Ewigkeiten MessageNumberBox aus lmacros.goh zur Kontrollanzeige von Variablen (hab ich mal von dir bekommen?). Ich habe die Datei in die process.goc eingebunden und den Code um MessageNumberBox - Zeilen ergänzt. Jetzt zeigen deine PrintNum und "meine" MessageNumberBox beide die falschen Rundungswerte. Was ist da los:?::?::?:

    Wilfried

  • Hallo Wilfried,

    ja, MessageNumberBox und lmacros.goh hast du wohl mal von mir, vermute ich. Allerdings kann meine MessageNumberBox eigentlich nur mit ganzen Zahlen umgehen (wegen der LocalFixedToAscii-Zeile), nicht mit Real-Zahlen. Angewendet auf result sollte a) eine Compilerwarung (type-fehler) kommen und b) nicht das richte Ergebnis angezeigt werden. Immer vorausgesetzt du nutzt meine MessageNumberBox().
    Außerdem hat die usprüngliche Variante aus lmacros.goh (die du wahrscheinlich hast) einen Bug, der buffer txt[] für LocalFixedToAscii war in bestimmten Situationen zu klein. Damit überscheibt LocalFixedToASCII igendwelchen Speicher auf dem Stack - das Ergebnis ist völlig unvorhersehbar. Das ist die aktuelle Version (mit txt[20]):

    Code
    #ifndef MessageNumberBox
    #define  MessageNumberBox(number) { \
            char txt[20]; \
            LocalFixedToAscii(txt,MakeWWFixed(number),0); \
            UserStandardDialog ( (char *)0,(char *)0,(char *)0,(char *)0,txt, \
            (( CDT_NOTIFICATION << CDBF_DIALOG_TYPE_OFFSET) | \
             ( GIT_NOTIFICATION << CDBF_INTERACTION_TYPE_OFFSET)) ); \
             }
    #endif


    Wenn ich richtig liege solltest du am Anfang (vor dem ersten Aufruf von MessageNumberBox) mal die Zeilen

    Code
    Print("\rRunde 3.86, 1 -> Wilfried: 3.9");
    result = round(3.86,1);
    PrintNum(result);

    Ändern in (minuszeichen hinzugefügt)

    Code
    Print("\rRunde -3.86, 1 -> ..");
    result = round(-3.86,1);
    PrintNum(result);

    Und das Ergebnis sollte richtig sein.

    Außerdem sollte die Korrektur des Macros MessageNumberBox() zumindest dazu führen, das PrintNum in der ganzen Sequenz die richtigen Ergebnisse liefert.

    Bis dahin erst mal
    Rainer

    P.S. Das Macro MakeWWFixed() ist wohl auch nicht perfekt, insbesondere wenn es um negative Zahlen geht.

    P.P.S. Du kannst dir gar nicht vorstellen, wie oft es mir schon passiert ist dass ein Programmabsturz oder ein anderer Fehler eigentlich gar nicht da war, sondern nur durch meinen "Ich-check-das-mal-zur-Sicherheit-gegen" Debuging Code hervorgerufen wurde. Das kostet oft Stunden! Trotzdem liebe ich das System :)

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

  • Hi Rainer,

    bezüglich MakeWWFixed gab es im Kontext zu Watcom ein Thema und einen Fix. Er akzeptiert da tatsächlich auch Floats/double und läßt diese den Compiler in ein dword casten, korrekterweise in ein sdword, was ich aber erst Fixen mußte. Borland hat binär beim cast nach dword/sdword immer mit Vorzeichen gearbeitet, Watcom beachtet den Zieltyp. Deswegen muß das MakeWWFixed-Makro korrigiert werden:

    943 fp math lib integration (#946) · bluewaysw/pcgeos@dd27ea5
    * Add dword unsigend conversion with float because Watcom integration will need it #943 * Add DLL to link for float runtime dependencies of Watcom C Compiler…
    github.com

    Viele Grüße,

    Falk \\ bluway.Softworks