Wysłano do SO kilka pytań dotyczących reprezentacji zmiennoprzecinkowej. Na przykład liczba dziesiętna 0,1 nie ma dokładnej reprezentacji binarnej, więc użycie operatora == w celu porównania jej z inną liczbą zmiennoprzecinkową jest niebezpieczne. Rozumiem zasady reprezentacji zmiennoprzecinkowej.
Nie rozumiem, dlaczego, z matematycznego punktu widzenia, liczby po prawej stronie przecinka są już bardziej „specjalne” niż te po lewej?
Na przykład liczba 61.0 ma dokładną reprezentację binarną, ponieważ integralna część dowolnej liczby jest zawsze dokładna. Ale liczba 6.10 nie jest dokładna. Wszystko, co zrobiłem, to przesunięcie dziesiętnego o jedno miejsce i nagle przeszedłem z Exactopia do Inexactville. Matematycznie nie powinno być żadnej istotnej różnicy między tymi dwiema liczbami - to tylko liczby.
Dla kontrastu, jeśli przesunę miejsce po przecinku o jedno miejsce w drugim kierunku, aby uzyskać liczbę 610, nadal będę w stanie Exactopia. Mogę iść w tym kierunku (6100, 610000000, 610000000000000) i nadal są dokładne, dokładne, dokładne. Ale gdy tylko liczba dziesiętna przekroczy pewien próg, liczby nie są już dokładne.
Co się dzieje?
Edycja: aby wyjaśnić, chcę trzymać się z dala od dyskusji na temat standardowych reprezentacji branżowych, takich jak IEEE, i trzymać się tego, co uważam za matematycznie „czysty” sposób. W podstawie 10 wartościami pozycyjnymi są:
... 1000 100 10 1 1/10 1/100 ...
W systemie dwójkowym byłyby to:
... 8 4 2 1 1/2 1/4 1/8 ...
Nie ma także żadnych arbitralnych ograniczeń dotyczących tych liczb. Pozycje zwiększają się w nieskończoność w lewo i w prawo.
źródło
Odpowiedzi:
Liczby dziesiętne mogą być dokładnie reprezentowane, jeśli masz wystarczająco dużo miejsca - tylko nie zmiennoprzecinkowe liczby binarne . Jeśli używasz zmiennoprzecinkowego typu dziesiętnego (np.
System.Decimal
W .NET), wówczas można dokładnie przedstawić wiele wartości, których nie można dokładnie przedstawić w binarnym zmiennoprzecinkowym.Spójrzmy na to z innej strony - w bazie 10, z którą prawdopodobnie będziesz czuć się komfortowo, nie możesz dokładnie wyrazić 1/3. To 0.3333333 ... (cykliczne). Powód, dla którego nie możesz reprezentować 0,1 jako binarnej liczby zmiennoprzecinkowej, jest dokładnie z tego samego powodu. Możesz dokładnie przedstawić 3, 9 i 27 - ale nie 1/3, 1/9 lub 1/27.
Problem polega na tym, że liczba 3 jest liczbą pierwszą, która nie jest dziesięciokrotna. Nie jest to problemem, gdy chcesz pomnożyć liczbę przez 3: zawsze możesz pomnożyć liczbę całkowitą bez żadnych problemów. Ale kiedy dzielisz przez liczbę pierwszą, która nie jest czynnikiem twojej bazy, możesz wpaść w kłopoty (i będzie to zrobić, jeśli starają się podzielić 1 przez tego numeru).
Chociaż 0,1 jest zwykle używany jako najprostszy przykład dokładnej liczby dziesiętnej, której nie można dokładnie przedstawić w binarnym zmiennoprzecinkowym, prawdopodobnie 0,2 jest prostszym przykładem, ponieważ wynosi 1/5 - a 5 jest liczbą pierwszą, która powoduje problemy między dziesiętną a binarną .
Uwaga dodatkowa dotycząca problemu reprezentacji skończonych:
Niektóre zmiennoprzecinkowe typy dziesiętne mają ustalony rozmiar, podobnie jak
System.Decimal
inne,java.math.BigDecimal
są „dowolnie duże” - ale w pewnym momencie przekroczą limit, czy to pamięć systemowa, czy teoretyczny maksymalny rozmiar tablicy. Jest to jednak zupełnie odrębny punkt od głównej tej odpowiedzi. Nawet jeśli miałbyś naprawdę dużą liczbę bitów do zabawy, nadal nie mógłbyś przedstawić dziesiętnej 0,1 dokładnie w postaci zmiennoprzecinkowej binarnej. Porównaj to z odwrót: podana dowolna liczba cyfr po przecinku, to może dokładnie reprezentować dowolną liczbę, która jest dokładnie to, przedstawianego jako zmiennoprzecinkowych binarnym.źródło
1
i reprezentację dziesiętną0.9...
(nieskończenie powtarzające się9
s po przecinku) są równe. Być może najłatwiejszym sposobem na sprawdzenie tego jest: Niech x =0.9...
. Zauważ, że10x = 9.9....
. Dlatego9x = 10x - x = 9.9... - 0.9... = 9
tak9x = 9
ix = 1
. Są inne sposoby, aby to zobaczyć, ale uważam, że jest to najprostsze.Odsuńmy się na chwilę od szczegółów baz 10 i 2. Zapytajmy - w bazie
b
, jakie liczby mają reprezentacje kończące, a które nie? Chwila namysłu mówi nam, że liczbax
mab
końcową reprezentację wtedy i tylko wtedy, gdy istnieje liczba całkowitan
taka, żex b^n
jest liczbą całkowitą.Na przykład
x = 11/500
ma kończącą się reprezentację 10, ponieważ możemy wybrać,n = 3
a następniex b^n = 22
liczbę całkowitą. Jednakx = 1/3
nie, ponieważ cokolwiekn
wybierzemy, nie będziemy w stanie pozbyć się 3.Ten drugi przykład skłania nas do zastanowienia się nad czynnikami i widzimy, że dla każdego racjonalnego
x = p/q
(zakładanego w najniższych kategoriach) możemy odpowiedzieć na pytanie, porównując podstawowe czynnikib
iq
. Jeśliq
jakieś czynniki pierwsze nie zostaną uwzględnione w pierwszej kolejnościb
, nigdy nie będziemy w stanie znaleźć odpowiedniegon
aby pozbyć się tych czynników.Tak więc, na podstawie 10, każdy
p/q
gdzieq
czynniki pierwsze są inne niż 2 lub 5, nie będą miały reprezentacji końcowej.Wracając teraz do baz 10 i 2, widzimy, że wszelkie racjonalne z kończącą się reprezentacją 10 będą miały postać
p/q
dokładnie wtedy, gdyq
dopiero2
y i5
y w swoim prime Faktoryzacji; i ta sama liczba będzie miała kończącą się reprezentację 2 dokładnie wtedy, gdyq
ma tylko2
swoje pierwsze rozkładanie na czynniki pierwsze.Ale jeden z tych przypadków jest podzbiorem drugiego! Kiedy tylko
oczywiście jest również prawdą
lub, inaczej mówiąc, ilekroć
p/q
ma końcową reprezentację 2,p/q
ma końcową reprezentację 10 . Odwrotna jednak ma nie posiadać - gdyq
ma 5 w swoim prime faktoryzacji, będzie to miało kończącą 10-reprezentacji, ale nie do kończącego 2-reprezentacji. To0.1
przykład wymieniony w innych odpowiedziach.Mamy więc odpowiedź na twoje pytanie - ponieważ czynniki pierwsze 2 są podzbiorem czynników pierwszych 10, wszystkie liczby kończące 2 są liczbami kończącymi 10, ale nie odwrotnie. Nie chodzi o 61 w porównaniu z 6.1 - to około 10 w porównaniu z 2.
Jako notatkę zamknięcia, jeśli przez niektórych ludzi dziwactwo używane (powiedzmy) podstawy 17, ale nasze komputery używane baza 5, twoja intuicja nigdy nie został uwiedziony przez to - nie byłoby żadne (niezerowe, non-integer) Liczby, które zakończone w obu przypadkach!
źródło
0.15
to tak naprawdę (gdy jest przechowywane jako podwójne IEEE) `0.149999999999999994448884876874`. Zobacz jsfiddle .Podstawowym (matematycznym) powodem jest to, że gdy mamy do czynienia z liczbami całkowitymi, są one w nieskończoność nieskończone .
Co oznacza, że chociaż jest ich nieskończona ilość, moglibyśmy „zliczyć” wszystkie elementy w sekwencji, nie pomijając żadnego. Oznacza to, że jeśli chcemy uzyskać pozycję na
610000000000000
tej pozycji na liście, możemy to ustalić za pomocą formuły.Jednak liczby rzeczywiste są niepoliczalnie nieskończone . Nie możesz powiedzieć „daj mi prawdziwą liczbę na stanowisku
610000000000000
” i uzyskaj odpowiedź. Powodem jest to, że nawet pomiędzy0
i1
istnieje nieskończona liczba wartości, gdy rozważasz wartości zmiennoprzecinkowe. To samo dotyczy dwóch dowolnych liczb zmiennoprzecinkowych.Więcej informacji:
http://en.wikipedia.org/wiki/Countable_set
http://en.wikipedia.org/wiki/Uncountable_set
Aktualizacja: przepraszam, chyba źle zinterpretowałem pytanie. Moja odpowiedź dotyczy tego, dlaczego nie możemy przedstawić każdej rzeczywistej wartości, nie zdawałem sobie sprawy, że zmiennoprzecinkowy jest automatycznie klasyfikowany jako racjonalny.
źródło
Powtórzyć to, co powiedziałem w moim komentarzu do pana Skeet: my może reprezentować 1/3, 1/9, 1/27, lub jakikolwiek racjonalny w notacji dziesiętnej. Robimy to, dodając dodatkowy symbol. Na przykład wiersz nad cyframi, które powtarzają się w dziesiętnym rozszerzeniu liczby. To, czego potrzebujemy do przedstawienia liczb dziesiętnych jako sekwencji liczb binarnych, to 1) sekwencja liczb binarnych, 2) punkt podstawy i 3) jakiś inny symbol wskazujący powtarzającą się część sekwencji.
Notacja cytatowa Hehnera jest na to sposobem. Używa symbolu cytatu do reprezentowania powtarzającej się części sekwencji. Artykuł: http://www.cs.toronto.edu/~hehner/ratno.pdf oraz wpis w Wikipedii: http://en.wikipedia.org/wiki/Quote_notation .
Nic nie mówi o tym, że nie możemy dodać symbolu do naszego systemu reprezentacji, więc możemy reprezentować liczby dziesiętne dokładnie za pomocą binarnej notacji cudzysłowów i odwrotnie.
źródło
BCD - binarnie dziesiętny - reprezentacje są dokładne. Nie zajmują dużo miejsca, ale jest to kompromis, który musisz wykonać w celu uzyskania dokładności w tym przypadku.
źródło
Jest to ten sam powód, dla którego nie możesz reprezentować 1/3 dokładnie w bazie 10, musisz powiedzieć 0.33333 (3). W systemie binarnym jest to ten sam typ problemu, ale występuje tylko dla innego zestawu liczb.
źródło
(Uwaga: dołączę „b”, aby wskazać tutaj liczby binarne. Wszystkie pozostałe liczby są podawane dziesiętnie)
Jednym ze sposobów myślenia o różnych rzeczach jest zapis naukowy. Przyzwyczailiśmy się widzieć liczby wyrażone w notacji naukowej, np. 6.022141 * 10 ^ 23. Liczby zmiennoprzecinkowe są przechowywane wewnętrznie w podobnym formacie - mantysa i wykładnik, ale przy użyciu potęg dwóch zamiast dziesięciu.
Twoje 61.0 może zostać przepisane jako 1.90625 * 2 ^ 5 lub 1.11101b * 2 ^ 101b z mantysą i wykładnikami potęgi. Aby pomnożyć to przez dziesięć i (przesunąć przecinek dziesiętny), możemy:
(1,90625 * 2 ^ 5) * (1,25 * 2 ^ 3) = (2,3828125 * 2 ^ 8) = (1,19140625 * 2 ^ 9)
lub z mantysą i wykładnikami w formacie binarnym:
(1,11101b * 2 ^ 101b) * (1,01b * 2 ^ 11b) = (10,0110001b * 2 ^ 1000b) = (1,00110001b * 2 ^ 1001b)
Zwróć uwagę na to, co zrobiliśmy, aby pomnożyć liczby. Pomnożymy mantysy i dodamy wykładniki. Następnie, ponieważ mantysa zakończyła się na więcej niż dwa, znormalizowaliśmy wynik, podnosząc wykładnik potęgi. To tak, jakbyśmy korygowali wykładnik po wykonaniu operacji na liczbach w dziesiętnej notacji naukowej. W każdym przypadku wartości, z którymi pracowaliśmy, miały skończoną reprezentację w formacie binarnym, a zatem wartości generowane przez podstawowe operacje mnożenia i dodawania również generowały wartości o skończonej reprezentacji.
Zastanówmy się teraz, jak podzielimy 61 przez 10. Zaczniemy od podzielenia mantysy, 1.90625 i 1.25. W ułamku dziesiętnym daje to 1,525 ładną krótką liczbę. Ale co to jest, jeśli przekonwertujemy go na binarny? Zrobimy to w zwykły sposób - odejmując największą możliwą potęgę dwóch, gdy tylko jest to możliwe, podobnie jak przekształcanie liczb całkowitych dziesiętnych na binarne, ale użyjemy ujemnych potęg dwóch:
O o. Teraz mamy kłopoty. Okazuje się, że 1,90625 / 1,25 = 1,525, jest ułamkiem powtarzalnym wyrażonym binarnie: 1.11101b / 1.01b = 1.10000110011 ... b Nasze maszyny mają tylko tyle bitów, aby utrzymać tę mantysę, więc zaokrągli ułamek i zakładamy zera powyżej pewnego punktu. Błąd, który widzisz, dzieląc 61 przez 10, jest różnicą między:
1.100001100110011001100110011001100110011 ... b * 2 ^ 10b
i, powiedzmy:
1.100001100110011001100110b * 2 ^ 10b
To zaokrąglenie mantysy prowadzi do utraty precyzji, którą kojarzymy z wartościami zmiennoprzecinkowymi. Nawet jeśli mantysę można wyrazić dokładnie (np. Po prostu dodając dwie liczby), nadal możemy uzyskać utratę liczbową, jeśli mantysa potrzebuje zbyt wielu cyfr, aby zmieścić się po normalizowaniu wykładnika.
W rzeczywistości robimy takie rzeczy przez cały czas, gdy zaokrąglamy liczby dziesiętne do rozsądnego rozmiaru i po prostu podajemy kilka pierwszych cyfr. Ponieważ wynik wyrażamy w postaci dziesiętnej, wydaje się to naturalne. Ale jeśli zaokrąglimy liczbę dziesiętną, a następnie przekonwertujemy ją na inną podstawę, wyglądałby tak samo brzydko, jak liczby dziesiętne, które otrzymujemy z powodu zaokrąglania zmiennoprzecinkowego.
źródło
To dobre pytanie.
Całe twoje pytanie dotyczy „w jaki sposób reprezentujemy liczbę?”
WSZYSTKIE liczby mogą być reprezentowane w postaci dziesiętnej lub binarnej (uzupełnienie 2). Wszyscy !!
ALE niektóre (większość z nich) wymagają nieskończonej liczby elementów („0” lub „1” dla pozycji binarnej lub „0”, „1” do „9” dla reprezentacji dziesiętnej).
Jak 1/3 w postaci dziesiętnej (1/3 = 0,33333333 ... <- z nieskończoną liczbą „3”)
Jak 0,1 w systemie binarnym (0,1 = 0,00011001100110011 .... <- z nieskończoną liczbą „0011”)
Wszystko jest w tej koncepcji. Ponieważ twój komputer może brać pod uwagę tylko skończony zestaw cyfr (dziesiętny lub binarny), tylko niektóre liczby mogą być dokładnie reprezentowane na twoim komputerze ...
I jak powiedział Jon, 3 jest liczbą pierwszą, która nie jest 10-krotna, więc 1/3 nie może być reprezentowana skończoną liczbą liczbę elementów w podstawie 10.
Nawet z arytmetyką z dowolną precyzją system pozycji numeracji w podstawie 2 nie jest w stanie w pełni opisać 6.1, chociaż może reprezentować 61.
W wersji 6.1 musimy użyć innej reprezentacji (jak reprezentacja dziesiętna lub IEEE 854, która zezwala na bazę 2 lub bazę 10 na reprezentację wartości zmiennoprzecinkowych)
źródło
Jeśli zrobisz wystarczająco dużą liczbę z liczbą zmiennoprzecinkową (ponieważ może to robić wykładniki), to skończysz z niedokładnością przed kropką dziesiętną. Nie sądzę więc, aby twoje pytanie było całkowicie uzasadnione, ponieważ przesłanka jest błędna; nie jest tak, że przesunięcie o 10 zawsze spowoduje większą precyzję, ponieważ w pewnym momencie liczba zmiennoprzecinkowa będzie musiała użyć wykładników wykładniczych do reprezentowania dużej liczby i również straci pewną precyzję w ten sposób.
źródło
Dziwi mnie, że nikt tego jeszcze nie powiedział: używaj ciągłych frakcji . Każda liczba wymierna może być w ten sposób skończona reprezentowana binarnie.
Kilka przykładów:
1/3 (0,3333 ...)
5/9 (0,5555 ...)
10/43 (0.232558139534883720930 ...)
9093/18478 (0,49209871198181621387596060179673 ...)
Stąd istnieje wiele znanych sposobów przechowywania sekwencji liczb całkowitych w pamięci.
Oprócz przechowywania liczby z idealną dokładnością, ciągłe ułamki mają również inne zalety, takie jak najlepsze racjonalne przybliżenie. Jeśli zdecydujesz się wcześniej zakończyć sekwencję liczb w ciągłym ułamku, pozostałe cyfry (po połączeniu w ułamek) dadzą najlepszą możliwą ułamek. W ten sposób można znaleźć przybliżenia liczby pi:
Ciągła frakcja Pi:
Kończąc sekwencję na 1, daje to ułamek:
355/113
co jest doskonałym racjonalnym przybliżeniem.
źródło
W równaniu
Dlatego zastanawiałem się, czy moglibyśmy mieć logarytmiczny system bazowy dla binarnych, takich jak,
To może rozwiązać problem, więc jeśli chcesz napisać coś takiego jak 32.41 w wersji binarnej, byłoby to możliwe
Lub
źródło
Problem polega na tym, że tak naprawdę nie wiesz, czy liczba faktycznie wynosi dokładnie 61,0. Rozważ to:
Jaka jest wartość c? Nie jest to dokładnie 61, ponieważ b nie jest tak naprawdę .1, ponieważ .1 nie ma dokładnej reprezentacji binarnej.
źródło
Istnieje próg, ponieważ znaczenie cyfry zmieniło się z liczby całkowitej na liczbę całkowitą. Aby przedstawić 61, masz 6 * 10 ^ 1 + 1 * 10 ^ 0; 10 ^ 1 i 10 ^ 0 są liczbami całkowitymi. 6.1 to 6 * 10 ^ 0 + 1 * 10 ^ -1, ale 10 ^ -1 to 1/10, co zdecydowanie nie jest liczbą całkowitą. Tak trafiasz do Inexactville.
źródło
Paralelę można utworzyć z ułamków i liczb całkowitych. Niektóre ułamki, np. 1/7, nie mogą być reprezentowane w postaci dziesiętnej bez partii i partii dziesiętnych. Ponieważ zmiennoprzecinkowy jest oparty na binarnych przypadkach, specjalne przypadki zmieniają się, ale pojawiają się te same problemy z dokładnością.
źródło
Istnieje nieskończona liczba liczb wymiernych i skończona liczba bitów, za pomocą których można je reprezentować. Zobacz http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems .
źródło
Liczba 61.0 rzeczywiście ma dokładną operację zmiennoprzecinkową - ale nie jest to prawdą dla wszystkich liczb całkowitych. Jeśli napisałeś pętlę, która dodała jedną do liczby zmiennoprzecinkowej podwójnej precyzji i 64-bitowej liczby całkowitej, w końcu osiągnąłbyś punkt, w którym 64-bitowa liczba całkowita doskonale reprezentuje liczbę, ale liczba zmiennoprzecinkowa nie… ponieważ nie ma wystarczającej ilości znaczących bitów.
O wiele łatwiej jest dotrzeć do punktu przybliżenia po prawej stronie przecinka dziesiętnego. Gdybyś zaczął zapisywać wszystkie liczby w binarnym zmiennoprzecinkowym, miałoby to większy sens.
Innym sposobem myślenia o tym jest to, że gdy zauważysz, że 61,0 jest doskonale reprezentowalne w podstawie 10, a przesunięcie punktu dziesiętnego wokoło tego nie zmieni, to wykonujesz mnożenie przez potęgi dziesięciu (10 ^ 1, 10 ^ -1 ). W zmiennoprzecinkowym pomnożenie przez potęgę dwóch nie wpływa na dokładność liczby. Spróbuj wziąć 61,0 i wielokrotnie dzieląc go przez trzy, aby zilustrować, jak idealnie precyzyjna liczba może utracić swoją dokładną reprezentację.
źródło
znasz liczby całkowite, prawda? każdy bit reprezentuje 2 ^ n
2 ^ 4 = 16
2 ^ 3 = 8
2 ^ 2 = 4
2 ^ 1 = 2
2 ^ 0 = 1
cóż, to samo dla zmiennoprzecinkowego (z pewnymi różnicami), ale bity reprezentują 2 ^ -n 2 ^ -1 = 1/2 = 0,5
2 ^ -2 = 1 / (2 * 2) = 0,25
2 ^ -3 = 0,125
2 ^ -4 = 0,0625
Reprezentacja binarna zmiennoprzecinkowa:
znak Ułamek wykładniczy (myślę, że niewidoczny 1 jest dołączony do ułamka)
B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0
źródło
Wyżej wymieniona odpowiedź o wysokiej punktacji przybiła ją.
Najpierw miksowałeś bazę 2 i bazę 10 w swoim pytaniu, a następnie, gdy umieścisz liczbę po prawej stronie, która nie jest podzielna na bazę, masz problemy. Jak 1/3 w systemie dziesiętnym, ponieważ 3 nie wchodzi w potęgę 10 lub 1/5 w systemie binarnym, co nie przechodzi w potęgę 2.
Kolejny komentarz NIGDY nie jest równy liczbom zmiennoprzecinkowym kropka. Nawet jeśli jest to dokładna reprezentacja, istnieją pewne liczby w niektórych systemach zmiennoprzecinkowych, które mogą być dokładnie reprezentowane na więcej niż jeden sposób (IEEE jest w tym złym, jest to okropna specyfikacja zmiennoprzecinkowa na początek, więc spodziewaj się bólów głowy). Nic innego tutaj 1/3 nie jest RÓWNE dla liczby na kalkulatorze 0,333 3333, bez względu na to, ile jest 3 po prawej stronie przecinka dziesiętnego. Jest lub może być wystarczająco blisko, ale nie jest równy. więc można oczekiwać, że coś w rodzaju 2 * 1/3 nie będzie równe 2/3 w zależności od zaokrąglenia. Nigdy nie używaj równego z zmiennoprzecinkowym.
źródło
Jak dyskutowaliśmy, w arytmetyce zmiennoprzecinkowej dziesiętne 0,1 nie może być idealnie reprezentowane w postaci binarnej.
Reprezentacje zmiennoprzecinkowe i liczby całkowite zapewniają siatki lub siatki dla reprezentowanych liczb. Po dokonaniu arytmetyki wyniki spadają z siatki i muszą być ponownie umieszczone na siatce zaokrąglając. Przykładem jest 1/10 na siatce binarnej.
Jeśli użyjemy binarnej reprezentacji dziesiętnej, jak sugerował jeden dżentelmen, czy bylibyśmy w stanie utrzymać liczby na siatce?
źródło