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?
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?
Odpowiedzi:
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
double
i 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.
Długa odpowiedź:
Liczby zmiennoprzecinkowe mają trzy składniki:
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 n
bitó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 n
jest 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 ≥ 1
Przynajmniej - 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 )
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 .
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.
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 + 1
plony value
, ponieważ value + 1
nie mogą być kodowane przy użyciu m * b ^ e
, gdzie m
, b
i e
są 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 n
cyfr, jak w przypadku liczb stałych, ponieważ nie każda liczba z n
cyframi 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 .
Spójrz na Float.intBitsToFloat
i Double.longBitsToDouble
, które wyjaśnią, w jaki sposób bity odpowiadają liczbom zmiennoprzecinkowym. W szczególności kawałki normalnego float
wyglą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.