Java double
są w formacie IEEE-754 , dlatego mają ułamek 52-bitowy; między dowolnymi dwoma sąsiednimi potęgami dwóch (włączając jedną i wyłączając następną), będą zatem od 2 do 52 różnych potęg double
(tj. 4503599627370496 z nich). Na przykład jest to liczba odrębnych double
s od 0,5 uwzględnionego do 1,0 wykluczonego, a dokładnie tyle znajduje się również między 1,0 włączonym a 2,0 wykluczonym i tak dalej.
Liczenie doubles
między 0,0 a 1,0 jest trudniejsze niż robienie tego między potęgami dwójki, ponieważ w tym zakresie jest wiele potęg dwójki, a ponadto można dostać się do drażliwych kwestii zdenormalizowanych liczb. 10 z 11 bitów wykładników obejmuje omawiany zakres, więc włączając zdenormalizowane liczby (i myślę, że kilka ich rodzajów NaN
), mielibyście 1024 razy double
więcej niż s między potęgami dwóch - i tak nie więcej niż 2**62
w sumie . Nie licząc zdenormalizowanych & c, uważam, że liczba wyniosłaby 1023 razy 2**52
.
W przypadku dowolnego zakresu, takiego jak „100 do 100,1”, jest to jeszcze trudniejsze, ponieważ górnej granicy nie można dokładnie przedstawić jako a double
(nie będącej dokładną wielokrotnością żadnej potęgi dwóch). Jako przydatne przybliżenie, ponieważ progresja między potęgami dwójki jest liniowa, można powiedzieć, że wspomniany zakres jest 0.1 / 64
tym odstępem między potęgami otaczającymi dwójki (64 i 128), więc można by się spodziewać
(0.1 / 64) * 2**52
odrębne double
s - które sprowadzają się do 7036874417766.4004
... dawania lub brania jednego lub dwóch ;-).
2**64
możliwych wartości podwójnych (ponieważ jest to typ 64-bitowy) i najwyraźniej OGROMNA część tych wartości leży pomiędzy0..1
?Każda
double
wartość, której reprezentacja znajduje się pomiędzy0x0000000000000000
i0x3ff0000000000000
leży w przedziale [0,0, 1,0]. To (2 ^ 62 - 2 ^ 52) różne wartości (plus lub minus kilka, w zależności od tego, czy liczysz punkty końcowe).Przedział [1,0, 2,0] odpowiada reprezentacjom między
0x3ff0000000000000
a0x400000000000000
; to jest 2 ^ 52 różne wartości.Przedział [100,0, 101,0] odpowiada reprezentacjom między
0x4059000000000000
a0x4059400000000000
; to jest 2 ^ 46 różnych wartości.Nie ma podwójnych między 10 ^ 100 a 10 ^ 100 + 1 . Żadnej z tych liczb nie można przedstawić z podwójną precyzją i nie ma między nimi podwójnych. Najbliższe dwie liczby podwójnej precyzji to:
i
źródło
Inni już wyjaśnili, że w zakresie [0,0, 1,0] jest około 2 ^ 62 dubli.
(Nie bardzo zaskakujące jest prawie 2 ^ 64 odrębne skończonych podwójna, z tych pół są pozytywne, a w przybliżeniu połowę tych wynoszą <1,0).
Ale wspomniałeś o generatorach liczb losowych: zwróć uwagę, że generator liczb losowych generujący liczby od 0,0 do 1,0 nie może generalnie wytworzyć wszystkich tych liczb; zazwyczaj tworzy tylko liczby w postaci n / 2 ^ 53, gdzie n jest liczbą całkowitą (zobacz np. dokumentację języka Java dla nextDouble ). Zatem zwykle jest tylko około 2 ^ 53 (+/- 1, w zależności od uwzględnionych punktów końcowych) możliwych wartości danych
random()
wyjściowych. Oznacza to, że większość dubletów w [0.0, 1.0] nigdy nie zostanie wygenerowana.źródło
Artykuł Nowa matematyka Java, Część 2: Liczby zmiennoprzecinkowe od IBM oferuje następujący fragment kodu, aby rozwiązać ten problem (w liczbach zmiennoprzecinkowych , ale podejrzewam, że działa również w przypadku podwójnych):
Mają na ten temat następujący komentarz:
źródło
float
, niedouble
-float
s ma wartość 23 bitów frakcji, więc2**23 -> 8388608
różne wartości między sąsiednimi uprawnień obydwoma ( «włącznie» część oczywiście znaczy, trzeba liczyć jeden więcej, następnego moc dwóch).double
mają ułamki 52-bitowe!double
odpowiednik i pomyślałem: „Hej, odpowiem na swoje pytanie za około 5 minut ...”double
potrzebującej zaledwie nanosekundy, aby uruchomić wewnętrzną pętlę, liczenie między sąsiednimi potęgami dwóch zajęłoby około 52 dni (println
oczywiście byłoby bardzo mało prawdopodobne, aby działał tak szybko bez względu na wszystko, więc załóżmy, że jedno stwierdzenie odchodzi ;-). Myślę, że można spędzić rok lub mniej na potężnej, ale realistycznej maszynie ;-).Więcej informacji znajdziesz w artykule na Wikipedii .
źródło
1
jest źle, bo ukryty jest zawsze jeden bit - Dlatego2^52
, nie2^53
odrębne wartości (między sąsiednimi uprawnień dwa, jeden wliczone w cenę i następnego wyłączone - nie ! Między 0,0 a 1,0).Podwójna Java to liczba binarna64 IEEE 754.
Oznacza to, że musimy wziąć pod uwagę:
Zasadniczo oznacza to, że istnieje łącznie 2 ^ 62-2 ^ 52 + 1 możliwych podwójnych reprezentacji, które zgodnie ze standardem mieszczą się w przedziale od 0 do 1. Należy zauważyć, że 2 ^ 52 + 1 ma na celu usunięcie przypadków nienormalizowanych liczby.
Pamiętaj, że jeśli mantysa jest dodatnia, ale wykładnik jest liczbą ujemną, liczba jest dodatnia, ale mniejsza niż 1 :-)
W przypadku innych liczb jest to nieco trudniejsze, ponieważ skrajne liczby całkowite mogą nie być reprezentowane w dokładny sposób w reprezentacji IEEE 754, a ponieważ istnieją inne bity używane w wykładniku, aby móc przedstawić liczby, więc im większa liczba, tym niższa różne wartości.
źródło