Rechnen mit Notes - was ist da los?

  • Ich habe einen Button in einer Maske, darüber hole ich mir über Ansichten Zahlen aus Dokumenten und summiere diese.
    So weit so gut. Am Schluss wird die eine Summe von der anderen abgezogen. Und hier kommt dann ein Ergebnis raus, das nicht stimmt. Ich kann mir das nicht erklären.
    Vielleicht hat jemand eine Idee, wie das zustande kommt.


    Damit der Text nicht zu lange wird, hier nur die wichtigen Sachen aus dem Code:


    Jetzt zu meinem Problem:
    Im Beispiel habe ich einen Kontostand von 3102,9 und offene Posten von 3102,9 - Die Differenz wäre als 0
    - Das Feld zeigt mir aber erstmal - im nicht gespeicherten Dokument die Zahl 1,81898940354586E-12 an.
    - Wenn ich das Dokument speichere o. mit F9 aktualisiere, dann wechselt die Zahl auf 0,000000000001819



    Warum ändert sich die Zahl nach F9 ?
    Vor allem: warum weist die Berechnung einen Unterschied aus, statt 0 auszugeben?


    Die Beträge, die summiert werden, haben alle maximal 2 Nachkommastellen.



    Der Fehler lässt sich im Übrigen beheben, indem ich die Round-Funktion einsetze:
    Call uidoc.FieldSetText("diff",Cstr(Round(d,2)))



    Aber ich hätte zu gerne eine Erklärung für das Ergebnis aus der Berechnung.



    Gruss
    Lizzy

  • Haben sie tatsächlich nur 2 Nachkommastellen oder werden lediglich 2 Nachkommastellen angezeigt ?
    Das ist ein wesentlicher Unterschied, denn Notes rechnet immer mit dem was tatsächlich im Feld steht und nicht was angezeigt wird.


    Wenn du per Script oder Formelsprache Werte in ein Feld schreibst stehen sie erst mal genau so drin, wie sie in der Formel/im Script berechnet wurden.
    Nach F9 greifen dann die Feldeigenschaften.


    Wenn du immer nur 2 Nachkommastellen hast würde ich immer entsprechend runden und dann so rechnen, sonst kommt es zu solchen Effekten

  • Die Zahlen haben wirklich alle nur eine oder zwei Nachkommastellen. Ich habe sie mir extra alle über die Dokumenteneigenschaften angesehen u. hier müsste ich ja die echte Zahl sehen.


    Das mit einer möglichen Änderung durch die Feldeigenschaften bei F9 versteh ich.
    Das Feld ist auf sich selbst berechnet, als Zahl mit zwei Nachkommastellen.



    Woher diese Differenz kommt, ist mir aber nach wie vor ein Rätsel

  • Was passiert, wenn du "k" und "o" nicht nur als Double definierst, sondern auch gleich noch mit "0" initialisierst?
    Was passiert weiters, wenn du "sum" nicht nur initialisierst, sondern auch explizit den Typen (bspw. "Double") setzt?
    Was sagt der Debugger an den Stellen
    - k = sum
    - o = sum
    - d = k - o (wo hast du "d" definiert?)
    zu den Werten und Typen?




    Was sagen die Feldeigenschaften an der Stelle "Call uidoc.FieldSetText("diff",Cstr(d))" für "diff"?


    Einer Variable nur den Typ, aber keinen Initialwert mitzugeben, kann -je nach Sprache und Betriebssystem- zu Problemen führen. Nicht zwangsläufig ist dann "0" (die Zahl Null) der default value. Das Problem hierbei ist der jeweilige Compiler oder Interpreter, der das u.U. nicht sauber verwaltet.
    Wird eine neue Variable instantiiert, wird -grob ausgedrückt- ein neuer Pointer auf den Stack geschoben. Der Pointer (wie der Name sagt) selbst hat keinen Value, sondern zeigt auf eine Speicheradresse. Mit Speicheradresse verhält es sich im Grunde (und wieder nur grob ausgedrückt), wie mit Dateisystemen: löscht man eine Datei, ist sie noch lange nicht weg, sondern nur der Block und ggf. alle Folgeblöcke werden als zum erneuten Gebraucht verwendbar bezeichnet. Das Bitmuster innerhalb der Blöcke bleibt allerdings erhalten, deswegen lassen sich gelöschte Dateien i.d.R. auch mit überschaubarem Aufwand recovern. Das Gleiche gilt für Speicheradressen: die Adresse selbst kann durchaus als zum erneuten Gebrauch freigegeben sein, allerdings befindet sich da ja mglw. noch etwas. Wenn jetzt der Compiler oder der Interpreter nicht aufpasst, wird der neue Zeiger plötzlich auf den Speicherinhalt "4711" zeigen (anstatt auf gähnende Leere) und die so instanziierte Variable wird implizit initialisiert.
    Es gibt allerdings eine Reihe von Mechanismen bei Windows und den Unixoiden, die genau das verhindern sollen. Vorrangig geht es dabei allerdings um SIcherheitsaspekte: wenn ein freigegebener Speicherbereich genullt wird, kann kein Schadprogramm der Welt durch Auslesen des Speichers an irgendwelche Informationen kommen. Vergleichbar mit bestimmten Löschprogrammen, die die Datei im Dateisystem nicht nur löschen, sondern mehrfach mit Nullen oder Zufallswerten überschreiben. Allerdings hat die Vergangenheit mehrfach gezeigt, dass beide Mechanismen nicht 100% zuverlässig vor ebensolchen Attacken oder Bugs schützen.


    Jetzt gibt es noch die Komiker, die meinen die Probleme der impliziten Variablenzuweisung damit lösen zu müssen, dass sie im Compiler oder Interpreter dahergehen und sowas spaßiges wie ($RANDOMVALUE/2^32) zum Default ernennen. Das könnte ganz dediziert die Erklärung für die augenscheinlich nicht erklärbare Differenz von 1.8E-12 sein.
    Da du zweimal mit Doubles arbeitest, einmal "sum" nur implizit instanziierst (wird IIRC erstmal ein INT und dann, wenn der Interpreter merkt, dass du plötzlich mit Doubles kommst, wird der INT auf Double gecastet) und dann auch nicht auf einen String castest, den du ins Dokument schreibst, sehe ich da durchaus eine Menge Potential für Vorbelegungsfehler (ohne dass ich den Entwicklern bei IBM zu nahe treten möchte).

    Life is not a journey to the grave with the intention of arriving safely in a pretty and well-preserved body, but rather to skid in broadside, thoroughly used up, totally worn out, and loudly proclaiming "Wow, what a ride!!! :evil:
    Beschleunigung ist, wenn die Tränen der Ergriffenheit waagrecht zum Ohr hin abfliessen - Walter Röhrl

    • Offizieller Beitrag

    Mit Call uidoc.FieldSetText("...",Cstr(...)) schreibst du einen Wert einer LotusScript-Variablen in ein Feld und dies als Text.
    Im Script wird die Variable als 1,81898940354586E-12 dargestellt. Die Darstellung bleibt auch im Feld so, weil du diese als Text ins Feld schreibst.
    Der Tastendruck auf F9 aktualisiert das Dokument und dabei wird die Zeichenkette in eine Zahl umgewandelt. In einem Feld wird die Zahl dann aber als 0,000000000001819 dargestellt.



    Zu den "Ungenauigkeiten":


    Es gibt nur 2 Möglichkeiten, wie diese zu stande kommen können.


    • Die Zahl wurde durch eine Berechnung erzeugt (insbesondere Division), dann entstehen schnell beliebig viele Nachkommastellen.
    • Durch Eintragen einer Zahl, die dann nur gerundet dargestellt wird (siehe taurecs Antwort). Dies passiert bei wesentlich kleineren Zahlen wie deine E-12.

    Viele Grüße
    Dirk

    Rein logisches Denken verschafft uns keine Erkenntnis über die wirkliche Welt.
    Alle Erkenntnis der Wirklichkeit beginnt mit der Erfahrung und endet mit ihr.
    Alle Aussagen, zu denen man auf rein logischen Wegen kommt, sind, was die Realität angeht, vollkommen leer.
    Albert Einstein

  • Ich habe k und o mit 0 initialisiert, hatte ich nur nicht ins Forum mit rein kopiert.
    sum hatte ich ebenfalls als Double gesetzt - ich wollte im Forum den Code nur nicht so lang machen.
    d ebenfalls als Double und mit 0 initialisiert.


    Sorry, nächstes Mal schreib ich wieder mehr rein, mir ist klar, daß das auch noch wichtige Infos gewesen wären.



    Ich habe mir die Stellen im Debugger angesehen:


    k 3102,9 Double
    o 3102,9 Double
    d 1,081898940354586E-12 Double


    diff Type = 768 Wert = 1,081898940354586E-12



    Eine Division hab ich nicht drin.
    k und o sind Summen eines Feldes über mehrere Dokumente
    d ist das Ergebnis einer Minus-Rechnung: k - o


    heisst: 3102,9 - 3102,9 = 1,081898940354586E-12


    werd ich wohl unter 'unerklärliche Dinge' abhaken müssen?!

  • Hallo Lizzy,


    Dein Problem hat nichts mit Domino, Lotusskript oder ähnlichem zu tun.


    Intern werden Zahlen binär im Format IEEE 754 gespeichert.
    Um Zahle dezimal darzustellen, müssen diese in eine Dezimalzahl konvertiert werden.
    Da es im Dezimal-Zahlensystem Zahlen gibt, die binär nicht als endliche Zahl dargestellt werden können (z.B. 0,1) entstehen in Binärformat periodische Zahlen, die aufgrund der endlichen Mantisse immer eine Ungenauigkeit beinhalten.
    Während einer Berechnung werden Rundungen ausgeführt um derartige Fehler möglichst klein zu halten.


    Wenn Du also mit monetären Werten rechnen möchtest ohne Gefahr zu laufen derartig merkwürdige Fehler zu erhalten solltest Du den Zahlentyp "Currency" verwenden.


    Bei Currency wird intern immer mit langen Integerzahlen gerechnet und für die Darstellung, Weiterverarbeitung (Konvertierung) der Wert einfach durch 10000 dividiert.
    Man hat also eine Zahl mit 4 Nachkommastellen ohne die Binärbruchproblmatik.


    Wenn Dir die Auflösung oder der Zahlenbereich von Currency nicht reicht kannst Du auch eine entsprechende Library wie die Concloo HighPrecision verwenden. Mit solchen Paketen ist es möglich Berechnung Dezimal mit etlichen Tausend bis Millionen Stellen auszuführen.


    Gruß Thorsten

  • Hallo Thorsten,


    jetzt wird es klarer.


    Ich hab mir mal im Internet einen Umrechner binär/dezimal gesucht. Da ist das schön zu sehen, was aus 0,1 wird.


    Jetzt ist mir auch klar, warum das nicht immer auftritt.
    Wenn ich halbwegs gerade Zahlen habe, dann passt es. Wenn aber Zahlen wie 1,27 oder 22,14 dabei sind, dann tritt das Problem auf.
    Das wird dann binär einfach zu lang und dann stimmt die Rundung nicht mehr, richtig?


    Ich hab das jetzt mit Currency versucht und hier passt alles.


    Danke und Gruss
    Lizzy

  • Hallo zusammen,


    kann es sein, dass das Ganze auch in der Formelsprache zu Problemen führt?
    Habe hier eine ähnliche Konstallation:


    Meine Formel:
    VAR1-VAR2-VAR3-VAR4+VAR5=0,000000000014552


    Ausgabe der einzelnen Variablen (@Text(VAR1)-@TEXT(VAR2)-@TEXT(VAR3)-@TEXT(VAR4)+@Text(VAR5)) ergibt: 0-47151,8--47451,8-300+0 und dies ist wiederum genau 0.


    Wenn ich mir die Feldinhalte ansehe (Eigenschaften vom Feld) sehe ich auch genau die "kurzen" Werte.
    Im Ergebnisfeld jedoch den Wert mit den zig Nachkommastellen. Muss man das verstehen?


    Viele Grüße


    Marc

  • Hallo Marc,


    die angezeigten einzelnen Feldwerte sind immer Ergebnis einer Umwandlung von Binär nach Dezimal.
    Bei dieser Umwandlung wird in der Regel gerundet um ein Anzeigeergebnis zu erhalten, dass dem Ursprungswert am nächsten kommt.
    Während einer Rechnung wird stets mit den Binärdaten gerechnet. Dies führt dann im Ergebnis zu Ungenauigkeiten im Vergleich zur manuellen Berechnung der ursprünglichen Dezimal-Werte.


    Sollte mit monetären Werten gerechnet werden kann ich nur den Datentyp Currency empfehlen.
    Für alle anderen Berechnung, bei denen auf erhöhte Genauigkeit ankommt sollten entsprechende Libraries verwenden werden, die mit nahezu beliebiger Genauigkeit/Stellenzahl (Exponent + Mantisse) und vor allem Dezimal rechnen.


    Gruß Thorsten