Warum ist Math.sqrt (i * i) .floor == ich?

8

Ich frage mich, ob das wahr ist: Wenn ich die Quadratwurzel einer quadrierten Ganzzahl verwende, wie in

%Vor%

Ich werde eine Gleitkommazahl erhalten, die sehr nahe bei 123 liegt. Aufgrund der Gleitkommadarstellungsgenauigkeit könnte dies etwa 122,999999999999999999999 oder 123,000000000000000000001 sein.

Da floor(122.999999999999999999) 122 ist, sollte ich 122 statt 123 bekommen. Also erwarte ich das floor(sqrt(i*i)) == i-1 in etwa 50% der Fälle. Komischerweise, für alle Zahlen, die ich getestet habe, floor(sqrt(i*i) == i . Hier ist ein kleines Ruby-Skript, um die ersten 100 Millionen Zahlen zu testen:

%Vor%

Das obige Skript gibt niemals etwas aus. Warum ist das so?

UPDATE: Danke für die schnelle Antwort, das scheint die Lösung zu sein: Nach wikipedia

  

Jede ganze Zahl mit absolutem Wert weniger   gleich oder gleich 2 ^ 24 kann genau sein   in der einfachen Genauigkeit dargestellt   Format und jede Ganzzahl mit absoluter   Wert kleiner als oder gleich 2 ^ 53 kann   im Doppel exakt dargestellt werden   Präzisionsformat.

Math.sqrt (i * i) beginnt sich so zu verhalten, wie ich es erwartet habe, beginnend mit i = 9007199254740993, was 2 ^ 53 + 1 ist.

    
martinus 13.01.2010, 21:40
quelle

4 Antworten

15

Für "kleine" Ganzzahlen gibt es normalerweise eine exakte Gleitkommadarstellung.

    
Anon. 13.01.2010, 21:42
quelle
22

Hier ist die Essenz Ihrer Verwirrung:

  

Aufgrund der Gleitkommadarstellung   Präzision, das könnte etwas sein   wie 122,999999999999999999999 oder   123.000000000000000000001.

Das ist falsch. Es wird immer genau 123 auf einem IEEE-754-konformen System sein, was fast alle Systeme in diesen modernen Zeiten sind. Fließkomma-Arithmetik hat keinen "zufälligen Fehler" oder "Rauschen". Es hat eine präzise, ​​deterministische Rundung, und viele einfache Berechnungen (wie diese) ergeben überhaupt keine Rundung.

123 ist genau in Gleitkomma darstellbar, und so ist 123*123 (also sind alle ganze Zahlen in bescheidener Größe). Daher tritt beim Konvertieren von 123*123 in einen Fließkommatyp kein Rundungsfehler auf. Das Ergebnis ist genau 15129 .

Quadratwurzel ist eine korrekt gerundete Operation gemäß dem IEEE-754-Standard. Dies bedeutet, dass, wenn es eine genaue Antwort gibt, die Quadratwurzelfunktion benötigt wird, um sie zu erzeugen. Da Sie die Quadratwurzel von genau 15129 nehmen, was genau 123 ist, ist das genau das Ergebnis, das Sie vom Quadrat erhalten Wurzelfunktion. Es findet keine Rundung oder Annäherung statt.

Nun, für wie groß einer ganzen Zahl wird das wahr sein?

Die doppelte Genauigkeit kann genau alle Ganzzahlen bis 2 ^ 53 darstellen. Solange also i*i kleiner als 2 ^ 53 ist, wird bei Ihrer Berechnung keine Rundung auftreten, und das Ergebnis wird genau deshalb sein. Dies bedeutet, dass wir für alle i kleiner als 94906265 wissen, dass die Berechnung genau ist.

Aber du hast i größer als das versucht! Was ist los?

Für die größte i , die Sie versucht haben, ist i*i nur knapp größer als 2 ^ 53 ( 1.1102... * 2^53 , eigentlich). Da Konvertierungen von Integer in Double (oder Multiplikation in Double) auch korrekt gerundete Operationen sind, ist i*i der darstellbare Wert, der dem genauen Quadrat von i am nächsten kommt. In diesem Fall wird, da i*i 54 Bits breit ist, die Rundung in dem niedrigsten Bit stattfinden. So wissen wir das:

%Vor%

wobei rounding entweder -1,0, or 1 ist. Wenn die Rundung Null ist, dann ist das Quadrat genau, also ist die Quadratwurzel genau, so wissen wir bereits, dass Sie die richtige Antwort erhalten. Lassen Sie uns diesen Fall ignorieren.

Also schauen wir uns jetzt die Quadratwurzel von i*i +/- 1 an. Unter Verwendung einer Taylor-Reihenentwicklung ist der unendlich genaue (nicht gerundete) Wert dieser Quadratwurzel:

%Vor%

Nun ist es etwas fummelig zu sehen, ob Sie schon einmal eine Gleitkomma-Fehleranalyse durchgeführt haben, aber wenn Sie die Tatsache verwenden, dass i^2 > 2^53 ist, können Sie folgendes sehen:

%Vor% Der Ausdruck

ist kleiner als 2 ^ -54, was bedeutet, dass (da die Quadratwurzel korrekt gerundet ist und daher ihr Rundungsfehler kleiner als 2 ^ 54 sein muss), das gerundete Ergebnis des sqrt Funktion ist genau i .

Es stellt sich heraus, dass (mit einer ähnlichen Analyse) für jede genau darstellbare Gleitkommazahl x, genau x ist (xx), vorausgesetzt, dass die Zwischenberechnung von x*x nicht über- oder unterläuft. Die Rundungsmethode für diese Art der Berechnung ist also nur in der Repräsentation von x selbst möglich, weshalb Sie sie ab 2^53 + 1 (der kleinsten nicht darstellbaren Ganzzahl) sehen.

    
Stephen Canon 13.01.2010 22:18
quelle
7

Es ist nicht schwer, Fälle zu finden, in denen dies so aussieht wie erwartet:

%Vor%     
tadman 13.01.2010 21:44
quelle
3

Ruby's Float ist eine Gleitkommazahl mit doppelter Genauigkeit, was bedeutet, dass sie Zahlen mit (Faustregel) über 16 signifikante Dezimalziffern genau darstellen kann. Bei regulären Gleitkommazahlen mit einfacher Genauigkeit handelt es sich um signifikante 7 Ziffern.

Weitere Informationen finden Sie hier:

Was jeder Informatiker über Fließkomma-Arithmetik wissen sollte: Ссылка

    
psyho 13.01.2010 22:09
quelle

Tags und Links