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:
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.
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:
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:
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:
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.
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: Ссылка
Tags und Links ruby floating-point precision