Oto esencja twojego zamieszania:
Ze względu na zmiennoprzecinkowych reprezentacja precyzja, to może być coś jak 122.99999999999999999999 lub 123.000000000000000000001.
To jest fałszywe. Zawsze będzie dokładnie 123 na systemie zgodnym ze standardem IEEE-754, czyli prawie wszystkie systemy w tych czasach nowożytnych. Arytmetyki zmiennoprzecinkowej nie ma „przypadkowy błąd” lub „szum”. Posiada precyzyjny deterministyczny zaokrąglania i wielu prostych obliczeń (jak ten) nie ponosić żadnej zaokrąglenie w ogóle.
123
jest dokładnie reprezentowalna w zmiennoprzecinkowych, a więc jest 123*123
(tak są wszystkie skromny wielkości liczb całkowitych). Więc nie występuje błąd zaokrąglania podczas konwersji 123*123
na typ zmiennoprzecinkowy. Wynik to dokładnie15129
.
Pierwiastek kwadratowy to prawidłowo zaokrąglona operacja według standardu IEEE-754. Oznacza to, że jeśli istnieje dokładna odpowiedź, do jej wytworzenia wymagana jest funkcja pierwiastka kwadratowego. Ponieważ pacjent jest pierwiastek kwadratowy z dokładnie15129
, który jest dokładnie123
, to dokładnie wyniku, który się z funkcji pierwiastka kwadratowego. Nie ma zaokrąglenia ani przybliżenia.
Teraz, jak duże z liczby całkowitej będzie to prawda?
Podwójna precyzja może dokładnie przedstawiać wszystkie liczby całkowite do 2^53. Tak długo, jak i*i
jest mniej niż 2^53, nie będzie zaokrąglania w obliczeniach, a wynik będzie dokładny z tego powodu. Oznacza to, że dla wszystkich i
mniejszych niż 94906265
wiemy, że obliczenia będą dokładne.
Ale wypróbowałeś i
większy niż to! Co się dzieje?
W przypadku największego i
, którego próbujesz, i*i
jest zaledwie nieco większy niż 2^53 (faktycznie). Ponieważ konwersje z liczby całkowitej do podwójnej (lub mnożenia w podwójnej) są również odpowiednio zaokrąglone, to reprezentowana wartość jest najbliższa dokładnemu kwadratowi i
. W tym przypadku, ponieważ i*i
ma szerokość 54 bitów, zaokrąglenie nastąpi w bardzo najniższym bicie. Tak więc wiemy, że:
i*i as a double = the exact value of i*i + rounding
gdzie jest albo -1,0, or 1
. Jeśli zaokrąglenie wynosi zero, to kwadrat jest dokładny, więc pierwiastek kwadratowy jest dokładny, więc wiemy już, że otrzymujesz właściwą odpowiedź. Zignorujmy tę sprawę.
Więc teraz patrzymy na pierwiastek kwadratowy z i*i +/- 1
. Korzystanie z ekspansji szereg Taylora, nieskończenie precyzyjny (niezaokrąglona) wartość tego pierwiastka jest:
i * (1 +/- 1/(2i^2) + O(1/i^4))
Teraz jest to nieco fiddly aby sprawdzić, czy nie zrobili żadnych zmiennoprzecinkowych analizy błędu przed, ale jeśli wykorzystują fakt, że i^2 > 2^53
, można zobaczyć, że: Termin
1/(2i^2) + O(1/i^4)
jest mniejszy niż 2^-54, co oznacza, że (ponieważ pierwiastek kwadratowy jest poprawnie zaokrąglone, i stąd jego błąd zaokrąglenia musi być mniejszy niż 2^54), zaokrąglony wynik funkcji sqrt to dokładnie i
.
Okazuje się, że (z podobną analizą), dla każdej dokładnie reprezentowalnej liczby zmiennoprzecinkowej x, sqrt (x * x) jest dokładnie x (przy założeniu, że obliczenia pośrednie x*x
nie przekroczą lub nie będą miały wartości), więc jedyny sposób, w jaki można uzyskać zaokrąglenie dla tego typu obliczeń, jest reprezentowany przez samą x
, dlatego zaczyna się od 2^53 + 1
(najmniejszej niereprezentowalnej liczby całkowitej).
Możesz zmienić 'i = 0; 100000000.times {puts i; i + = 1} 'do' 100000000.times {| i | kładzie i} ' –
prawo, dzięki. jest teraz nieco prostszy. Tak, to jest – martinus