Fehler in der Gleitkommaarithmetik: Ist's einer oder nicht ?



  • hi

    @winn

    da hast du eines der hässlichen Probleme mit den Gleitkomma Arithmetik erwischt.

    Das Problem ligt im aufbau der Zahlen. Ich mach mal am besten ein kleines beispiel mit kleinen Zahlen. Genauigkeit 4 Nachkommastellen, damit kann man vileicht mehr sehen.

    Darstellung von zahlen in der Gelitkommaarithmetik geschieht in Exponentenschreibweise.
    100 000 = 1.0000 * 10 ^ 5
    1 = 1.0000 * 10 ^ 0

    Addition der beiden Zahlen
    1 000 000 + 1 = 1 000 001 das sollte rauskommen.
    1.0000 * 10 ^ 6 + 1.0000 * 10 ^ 0 = 1.000001 * 10 ^ 6

    in der Geitkommma Arrithmetik kann das wie oben nicht verechnet werden, da die exponenten ungleich sind. Sie müssen also angepasst werden, allso wird 1.0000 * 10 ^ 0 nach 0.00001 * 10 ^ 6 umgewandelt, da die mantisse maximal eine Stelle hat. Ergibt somit

    1.0000 * 10 ^ 6 + 0.000001 * 10 ^ 6

    liesse sich ja jetzt schon verrechnen. Mantissen adieren, und alles ist gut. ABER wir haben NUR eine Auflösung von 4 Nachkommastellen. Somit müssen wir 0.000001 * 10 ^ 6 mit 0.0000 * 10 ^ 6 darstellen. ( Darstellungsproblem kleiner Zahlen)

    1.0000 * 10 ^ 6 + 0.0000 * 10 ^ 5 = 1.0000 * 10 ^ 6

    und schon haben wir nen rechenfehler.

    lustiger wird das problem, wenn wir in einer schleife versuchen 1 000 000 mal die 1 auf 1 000 000 zu addieren, sollte ja 2 000 000 rauskommen nur ergibt sich nur 1 000 000 als ergibnis. ( voll daneben )

    Lösung dieses Problems: Alle zu addirenden Zahlen werden in einer Liste sortiert. Die beiden kleinsten Zahlen werden herausgenommen und addiert und wieder in die Liste eingefügt und anschliesend neu sortiert. Dieses Spiel widerholen wir solange bis wir das ergibnis haben. Durch das addieren von annähernd gleichen Zahlen, verringern wir die rundungsfehler und somit auch das zu null runden von Zahlen. Das ergibnis wird zwar auch nicht exakt sein, da wir ja dauernd Zahlen umrechnen und runden müssen, aber der Fehler ist kleinst möglichst.

    gruss termite



  • Das find ich ja mal richtig interessant !!! Also gibt es die Möglichkeit durch "unbequemes langes" rechnen, den Fehler in der Gleitkomma Arithmetik zu minimieren...

    Hab jetzt mal ein wenig weiter geforstet und die Fehler lassen sich klassifizieren:

    1. Rundungsfehler, Zahlen wie 2/3 werden als 0.66666667 dargestellt
    2. Absorbtion, Additionen wie 1*10^6 + 1 = 1*10^6 (siehe Termite)
    3. Abbruch, Subtraktionen wie 1,1*10^6 - 1*10^6 = 0 (also ähnlich wie die Absorbtion, aber ich finde - wesentlich fataler, wenn z.B. so etwas im Nenner steht !!)
    4. Overflow/Underflow entstehend aus den Fehlern Absorbtion/Abbruch kann es zum Überschreiten/Unterschreiten des darstellbaren Zahlenbereichs kommen.

    Was mich jetzt mal weiter interessieren würde ist, wie in der Gleitkomma Arithmetik multipliziert bzw. dividiert wird ?! Hab dazu erstmal nix gefunden, scheint auch unterschiedlich bzw. maschinenabhängig zu sein, da die Gleitkomma Darstellung einer Cray wohl abweichend von der IEEE Darstellung ist !! Oder ??



  • Hi

    Multiplikation sollte eigenlich recht einfach gehen.

    Mantissen multiplizieren, exponenten adieren und gut ist der laden.
    Dievison sollte änlich gehen. Mantissen dividieren, exponenten subtrahieren.

    Die exponentendarstellung von c find ich sowieso zum schreien, kann mir mal jemand sagen wozu man zahmen der grössenordung +/-3.4 * 10 ^ +/-4932 braucht ? ( long double) Zum wissenschaftlichen rechnen wohl kaum oder? vorallem reicht da die genauigkeit der mantisse nicht mehr aus.
    da sind andere systeme doch eindeitig besser. Weniger bits für den exponenten dafür mehr für die Mantisse.

    gruss Termite



  • Termite schrieb:

    Weniger bits für den exponenten dafür mehr für die Mantisse.

    Das sehe ich allerdings auch so !!! Denn meine Zahlen bewegen sich meist zwischen 10^(+30) und 10^(-30) ... da muß es doch etwas zu geben, irgendwer hat da doch bestimmt mal ne Lib (für C/C++) geschrieben, kann doch nicht sein, daß wir die Einzigen sind, die so etwas gerne hätten, oder ?? Nur nach welchen Begriffen sucht man dann ? Und wo ? SourceForge ?



  • Ich würde nach arbitrary precision library suchen 😉 .



  • Also es gibt auch die Möglichkeit Zahlen als Strings darzustellen und damit zu rechnen, das ist zwar elend lahm, aber man kann beinahe beliebig viele Stellen benutzen.
    Das hatte auch einen besonderen Namen, mit BCDs konnte man das machen , aber auch mit dem ascii Zeichensatz.



  • Interessante Option mit Strings zu arbeiten... allerdings frage ich mich direkt, wie die Strings verarbeitet werden ohne auch nur auf irgend eine Art von Gleitkommazahl zuzugreifen ?



  • Winn schrieb:

    Interessante Option mit Strings zu arbeiten... allerdings frage ich mich direkt, wie die Strings verarbeitet werden ohne auch nur auf irgend eine Art von Gleitkommazahl zuzugreifen ?

    Wahrscheinlich wird dann damit gerechnet wie in der Grundschule: "1 im Sinn" usw.
    Ich glaube das killt ein wenig die Performance. Schau dir doch mal boost::rational an. Ist auch ein interessanter Ansatz so etwas mit Bruchrechnung zu lösen.



  • Jo, genau so geht das. Allerdings nimmt man nicht unbedingt BCD, das ist zu arg, sondern eher zum Beispiel das 2^32er System. Damit wird eine Stelle durch ein DWORD kodiert und man hat keine überflüssigen Bits.
    Multiplikation kann man dann zum Beispiel mittels FFT implementieren (O(n*logn)), Addition geht in O(n), Division wird recht heftig... gibt's aber auch Algorithmen dazu.

    MfG Jester



  • Hmm, ich bin jetzt erstmal davon ausgegangen, daß die dort versuchen alles möglichst auf Integer Werte zu "übersetzen" ... ich denke es geht dabei in Richtung "Symbolic Computation"


Anmelden zum Antworten