8

Ich habe versucht, eine Funktion zu schreiben, um Quadratwurzeln zu approximieren (ich weiß, dass es das Mathematikmodul gibt ... Ich möchte es selbst machen), und ich wurde von der Fließkomma-Arithmetik durcheinander gebracht. Wie können Sie das vermeiden?Wie vermeidet man Gleitkommafehler?

def sqrt(num): 
    root = 0.0 
    while root * root < num: 
     root += 0.01 
    return root 

dieser Verwendung hat diese Ergebnisse:

>>> sqrt(4) 
2.0000000000000013 
>>> sqrt(9) 
3.00999999999998 

Ich weiß, ich nur round() verwenden könnte, aber ich möchte in der Lage sein, dies wirklich genau zu machen. Ich möchte in der Lage sein, 6 oder 7 Ziffern zu berechnen. Das wäre nicht möglich, wenn ich mich versehe. Ich möchte verstehen, wie man Gleitkommaberechnungen in Python richtig behandelt.

+0

Vielleicht versuchen, die [Dezimal] (http://docs.python.org/2/library/decimal.html) Modul, das ist auf Präzision ausgelegt? – Michael0x2a

Antwort

15

Das hat wirklich nichts mit Python zu tun - Sie würden das gleiche Verhalten in jeder Sprache mit der binären Fließkommaarithmetik Ihrer Hardware sehen. Zuerst read the docs.

Nachdem Sie das gelesen haben, werden Sie besser verstehen, dass Sie nicht hinzufügen ein hundertstel in Ihrem Code. Das ist genau das, was Sie fügte hinzu:

>>> from decimal import Decimal 
>>> Decimal(.01) 
Decimal('0.01000000000000000020816681711721685132943093776702880859375') 

Dieser String zeigt die genaue Dezimalwert der binären Floating („double precision“ in C) Annäherung an den exakten Dezimalwert 0,01. Die Sache, die du wirklich hinzufügst, ist etwas größer als 1/100.

Die Steuerung numerischer Gleitkommafehler ist das Feld "numerische Analyse" und ist ein sehr großes und komplexes Thema. Solange Sie sich darüber wundern, dass Gleitkommazahlen nur Näherungen für Dezimalwerte sind, verwenden Sie das Modul decimal. Das wird dir eine Welt von "oberflächlichen" Problemen nehmen.

from decimal import Decimal as D 

def sqrt(num): 
    root = D(0) 
    while root * root < num: 
     root += D("0.01") 
    return root 

dann: Zum Beispiel diese kleine Änderung Ihrer Funktion gegeben

>>> sqrt(4) 
Decimal('2.00') 
>>> sqrt(9) 
Decimal('3.00') 

Es ist nicht wirklich genauer, aber möglicherweise weniger überraschend in einfachen Beispielen, weil jetzt ist es genau man eine Zugabe -Hundertstel.

Eine Alternative ist, zu halten, etwas zu schwimmt, und fügen Sie die ist genau darstellbare als binäres float: Werte der Form I/2**J. Anstatt beispielsweise 0,01 hinzuzufügen, fügen Sie 0,125 (1/8) oder 0,0625 (1/16) hinzu.

Dann schlagen Sie unter „Newton-Verfahren“ zur Berechnung von Quadratwurzeln ;-)

+0

Für den Datensatz hatte ich die Dokumente gelesen und ich wusste bereits über die ganze Gleitkomma-Genauigkeit Sache mit dem Speichern binärer Darstellungen. Ich hatte Newtons Methode vergessen. Du nimmst alle meine Fragen hier auf! Mein Glückstag, als du SO entdeckt hast. Ich frage mich, wie das Dezimal-Modul funktioniert. Gibt es eine Möglichkeit, neben dem Lesen der Quelle herauszufinden? – Aerovistae

+1

Nun, 'decimal' wurde ursprünglich in Python geschrieben und arbeitete an Listen mit Dezimalziffern (0, 1, 2, ..., 9). Sehr emuliert, wie wir auf dem Papier rechnen! "Gleitkomma" erfordert nur das Hinzufügen eines (Dezimal-) Exponenten zur Darstellung und dann sehr vorsichtig ;-) Das aktuelle 'dezimale' Modul ist in C kodiert und ist viel obskurer :-( –

+0

wie gesagt, ich habe es versucht "4 - 3.2" mit dezimalem Modul lösen. a = Dezimal (4) b = Dezimal (3.2) aber a - b Ergebnis ist Dezimal (',7999999999999998223643160600') – Srinesh

Verwandte Themen