Ile znaczących cyfr mają liczby zmiennoprzecinkowe i podwójne w języku Java?

83

Czy liczba zmiennoprzecinkowa ma 32 cyfry binarne, a podwójna 64 cyfry binarne? Dokumentacja była zbyt trudna do zrozumienia.

Czy wszystkie bity są tłumaczone na cyfry znaczące? A może położenie przecinka dziesiętnego zajmuje część bitów?

Eamon Moloney
źródło
2
Czy wszystkie te bity są tłumaczone na cyfry znaczące? A może położenie przecinka dziesiętnego zajmuje część bitów?
Eamon Moloney
@ user1774214 liczby zmiennoprzecinkowe nie są w ogóle kodowane jak liczby całkowite. spójrz na link, który podam. Musisz na przykład zrozumieć, że precyzja nie jest jednolita.
Denys Séguret
@dystroy Nie jestem pewien, co masz na myśli mówiąc „precyzja nie jest jednolita”. Jest to dość jednolite 53 i 24 bity precyzji, chyba że odnosisz się do denormali.
Pascal Cuoq
2
@PascalCuoq zapewnia większą precyzję w przypadku mniejszych liczb. Gdy wykładnik się zmienia (lub punkt pływa) wokół, mantysa reprezentuje tę samą liczbę cyfr. Więc jeśli liczba jest duża, mantysa „nie może osiągnąć” mniejszych cyfr znaczących, co daje mniejszą precyzję.
Vituel
3
@Virtuel Precyzja wynosi 53 bity. To właśnie nazywamy precyzją. Wydaje się, że myślisz o absolutnej dokładności lub o czymś takim.
Pascal Cuoq

Odpowiedzi:

108

float : 32 bity (4 bajty), gdzie mantysa ma 23 bity (około 7 cyfr dziesiętnych). 8 bitów jest używanych jako wykładnik, więc liczba zmiennoprzecinkowa może „przesuwać” przecinek dziesiętny w prawo lub w lewo za pomocą tych 8 bitów. W ten sposób unika się przechowywania wielu zer w mantysie, jak w 0,0000003 (3 × 10-7 ) lub 3000000 (3 × 10 7 ). Jako bit znaku używany jest 1 bit.

double : 64 bity (8 bajtów), gdzie mantysa ma 52 bity (około 16 cyfr dziesiętnych). 11 bitów jest używanych jako wykładnik, a 1 bit to bit znaku.

Ponieważ używamy liczby binarnej (tylko 0 i 1), jeden bit mantysy jest niejawnie równy 1 (zarówno zmiennoprzecinkowy, jak i podwójny używają tej sztuczki), gdy liczba jest różna od zera.

Ponadto, ponieważ wszystko jest binarne (mantysa i wykładniki), konwersje na liczby dziesiętne zwykle nie są dokładne. Liczby takie jak 0,5, 0,25, 0,75, 0,125 są przechowywane dokładnie, ale 0,1 nie. Jak powiedzieli inni, jeśli potrzebujesz precyzyjnie przechowywać centy, nie używaj float ani double, używaj int, long, BigInteger lub BigDecimal.

Źródła:

http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers

http://en.wikipedia.org/wiki/Binary64

http://en.wikipedia.org/wiki/Binary32

Marcus
źródło
co masz na myśli od 6 do 9? jak to może się zmienić? więc jeśli uruchomię kod, który ma 8 cyfr dziesiętnych, takich jak 0,000000001 wiele razy, otrzymam różne wyniki? czy o to Ci chodziło?
Aequitas
2
Niektóre liczby można przedstawić dokładniej w systemie dwójkowym niż inne. Możesz zobaczyć różnicę w 0,125 (1/8, osiem to potęga dwóch) i 0,1 (1/10, dziesięć to nie potęga dwóch). Pierwsza ma więcej cyfr (dziesiętnych), ale jest dokładnie reprezentowana. Może się więc zdarzyć, że liczba z 6 cyframi dziesiętnymi ma większe błędy zaokrąglenia niż inna liczba z 8 cyframi.
marcus
9
15,9 cyfr dziesiętnych dla doublei 7,2 dla float, czyli 15 i 7. W każdym przypadku można przedstawić niektóre większe liczby i żadna z nich nie dotyczy ułamków, ale nie ma o tym „średniej”, a żadne z twoich źródeł nie mówi Inaczej.
user207421
1
Jeśli nie podoba Ci się słowo „średnia”, zaproponuj zmianę. W pierwszej kolejności nie został dodany przeze mnie, został zredagowany przez kogoś innego ... (i naprawdę nie widziałem potrzeby takiej edycji).
marcus
4
Co ciekawe, w rzeczywistości istnieje jedna cyfra dokładności więcej niż przechowywana w mantysie / sztyfcie. 23 i 52 bity są przechowywane odpowiednio dla liczb zmiennoprzecinkowych i podwójnych, ale ponieważ liczby są znormalizowane, możemy założyć początkowy 1-bitowy, a następnie go pominąć. Dlatego efektywna precyzja wynosi odpowiednio 24 i 53 bity. Dokładne dokładności dziesiętne są obliczane jako log10 (2 ^ 24) = 7,22 i log10 (2 ^ 53) = 15,95
Georgie
32

32-bitowy zmiennoprzecinkowy ma około 7 cyfr dokładności, a 64-bitowy podwójny ma około 16 cyfr precyzji

Długa odpowiedź:

Liczby zmiennoprzecinkowe mają trzy składniki:

  1. Bit znaku określający, czy liczba jest dodatnia czy ujemna.
  2. Wykładnik określający wielkość liczby.
  3. Ułamek, który określa, jak daleko między dwoma wartościami wykładników znajduje się liczba. Nazywa się to czasem „znaczeniem, mantysą lub współczynnikiem”

Zasadniczo to działa sign * 2^exponent * (1 + fraction). „Rozmiar” liczby, jej wykładnik, nie ma dla nas znaczenia, ponieważ skaluje tylko wartość części ułamkowej. Wiedząc, że log₁₀(n)daje to liczbę cyfr n, † możemy określić dokładność liczby zmiennoprzecinkowej za pomocą log₁₀(largest_possible_fraction). Ponieważ każdy bit w liczbie zmiennoprzecinkowej przechowuje 2 możliwości, binarna liczba nbitów może przechowywać liczbę do 2ⁿ - 1(łącznie 2ⁿ wartości, w których jedna z wartości wynosi zero). Staje się to nieco bardziej skomplikowane, ponieważ okazuje się, że liczby zmiennoprzecinkowe są przechowywane z jednym bitem ułamka mniejszym, niż mogą użyć, ponieważ zera są reprezentowane specjalnie, a wszystkie liczby niezerowe mają co najmniej jeden niezerowy bit binarny. ‡ ‡

Łącząc to, cyfry dokładności dla liczby zmiennoprzecinkowej to log₁₀(2ⁿ), gdzie njest liczbą bitów ułamka liczby zmiennoprzecinkowej. 32-bitowa liczba zmiennoprzecinkowa ma 24 bity ułamka dla dokładności ≈7,22 cyfr dziesiętnych, a 64-bitowa podwójna ma 53 bity ułamka dla dokładności ≈15,95 cyfr dziesiętnych.

Aby uzyskać więcej informacji na temat dokładności zmiennoprzecinkowej, możesz przeczytać o koncepcji epsilon maszynowej .


n ≥ 1Przynajmniej - dla innych liczb Twój wzór będzie wyglądał bardziej jak ⌊log₁₀(|n|)⌋ + 1.

‡ „Reguła ta jest różnie nazywana konwencją bitów wiodących, niejawną konwencją bitową lub konwencją ukrytego bitu”. ( Wikipedia )

9999 lat
źródło
17

Ze specyfikacji Java :

Typy zmiennoprzecinkowe to zmiennoprzecinkowe i podwójne, które są koncepcyjnie powiązane z wartościami i operacjami w formacie IEEE 754 o pojedynczej precyzji 32-bitowej i podwójnej precyzji w 64-bitowym formacie, jak określono w IEEE Standard for Binary Floating-Point Arithmetic, ANSI / IEEE Standard 754-1985 (IEEE, Nowy Jork).

Ponieważ trudno jest zrobić cokolwiek z liczbami bez zrozumienia podstaw IEEE754, oto kolejny link .

Ważne jest, aby zrozumieć, że precyzja nie jest jednolita i że nie jest to dokładne przechowywanie liczb, jak ma to miejsce w przypadku liczb całkowitych.

Przykład :

double a = 0.3 - 0.1;
System.out.println(a);          

wydruki

0.19999999999999998

Jeśli potrzebujesz dowolnej precyzji (na przykład do celów finansowych), możesz potrzebować opcji Big Decimal .

Denys Séguret
źródło
7

Normalna odpowiedź matematyczna.

Rozumiejąc, że liczba zmiennoprzecinkowa jest zaimplementowana jako niektóre bity reprezentujące wykładnik, a pozostałe, w większości dla cyfr (w systemie binarnym), mamy następującą sytuację:

Przy wysokim wykładniku, powiedzmy 10²³, jeśli najmniej znaczący bit zostanie zmieniony, pojawi się duża różnica między dwoma sąsiednimi liczbami, które można odróżnić od siebie. Ponadto kropka dziesiętna o podstawie 2 sprawia, że ​​wiele liczb o podstawie 10 można jedynie przybliżać; 1/5, 1/10 to nieskończone liczby.

Tak w ogóle : liczb zmiennoprzecinkowych nie powinny być stosowane, jeżeli dbasz o znaczących cyfr. W przypadku kwot pieniężnych z obliczeniami, e, a, najlepiej używać BigDecimal .

Dla fizyka zmiennoprzecinkowej dwuosobowe są wystarczające, unosi się prawie nigdy. Ponadto zmiennoprzecinkowa część procesorów, FPU, może nawet wewnętrznie używać nieco większej precyzji.

Joop Eggen
źródło
3

Liczby zmiennoprzecinkowe są kodowane przy użyciu postaci wykładniczej, czyli czegoś w rodzaju m * b ^ e, tj. W ogóle nie są liczbami całkowitymi. Pytanie, które zadasz, miałoby znaczenie w kontekście liczb stałych punktów . Dostępnych jest wiele bibliotek arytmetycznych punktów stałych .

Odnośnie arytmetyki zmiennoprzecinkowej: Liczba cyfr dziesiętnych zależy od prezentacji i systemu liczbowego. Na przykład istnieją liczby okresowe ( 0.33333), które nie mają skończonej prezentacji w postaci dziesiętnej, ale mają ją w postaci binarnej i odwrotnie.

Również warto wspomnieć, że liczb zmiennoprzecinkowych do pewnego stopnia mają różnicę większą niż jeden, czyli value + 1plony value, ponieważ value + 1nie mogą być kodowane przy użyciu m * b ^ e, gdzie m, bi esą ustalone w długości. To samo dzieje się w przypadku wartości mniejszych niż 1, tj. Wszystkie możliwe punkty kodowe nie mają takiej samej odległości.

Z tego powodu nie ma precyzji dokładnych ncyfr, jak w przypadku liczb stałych, ponieważ nie każda liczba z ncyframi dziesiętnymi ma kodowanie IEEE.

Istnieje prawie obowiązkowy dokument, który powinieneś przeczytać, wyjaśniający liczby zmiennoprzecinkowe: Co każdy informatyk powinien wiedzieć o arytmetyce zmiennoprzecinkowej .

straszny
źródło
2
+1 za wzmiankę „Co każdy informatyk powinien wiedzieć o arytmetyce zmiennoprzecinkowej”. Warto jednak zauważyć, że każda liczba, która ma skończoną reprezentację ułamka binarnego, ma również skończoną reprezentację dziesiętną. Problem polega tylko na przejściu od dziesiętnego do dwójkowego.
Patricia Shanahan
1

Spójrz na Float.intBitsToFloati Double.longBitsToDouble, które wyjaśnią, w jaki sposób bity odpowiadają liczbom zmiennoprzecinkowym. W szczególności kawałki normalnego floatwyglądu przypominają

 s * 2^exp * 1.ABCDEFGHIJKLMNOPQRSTUVW

gdzie A ... W to 23 bity - 0 i 1 - reprezentujące ułamek w postaci binarnej - s to +/- 1, reprezentowane odpowiednio przez 0 lub 1, a exp jest 8-bitową liczbą całkowitą ze znakiem.

Louis Wasserman
źródło