Jaka jest pierwsza liczba całkowita, której zmiennoprzecinkowy IEEE 754 nie jest w stanie dokładnie przedstawić?

162

Dla jasności, jeśli używam języka, który implementuje zmiennoprzecinkowe IEE 754 i oświadczam:

float f0 = 0.f;
float f1 = 1.f;

... a następnie wydrukuj je z powrotem, otrzymam 0,0000 i 1,0000 - dokładnie.

Ale IEEE 754 nie jest w stanie przedstawić wszystkich liczb wzdłuż rzeczywistej linii. Bliskie zeru „luki” są małe; w miarę oddalania się odstępy się powiększają.

Więc moje pytanie brzmi: dla float IEEE 754, która jest pierwszą (najbliższą zeru) liczbą całkowitą, której nie można dokładnie przedstawić? Na razie jestem naprawdę zainteresowany tylko 32-bitowymi floatami, chociaż będę zainteresowany usłyszeniem odpowiedzi na 64-bitowe, jeśli ktoś ją poda!

Pomyślałem, że będzie to tak proste, jak obliczenie 2 bitów_mantissy i dodanie 1, gdzie bity_mantysy to liczba bitów ujawnionych przez standard. Zrobiłem to dla 32-bitowych pływaków na moim komputerze (MSVC ++, Win64) i wydawało się jednak w porządku.

Floomi
źródło
Dlaczego dodałeś jeden, skoro chciałeś mieć numer, którego nie da się przedstawić? A jakiego numeru użyłeś lub dostałeś? A czy to zadanie domowe? Tytuł pytania brzmi „liczba całkowita”, ale pytanie brzmi „liczba zmienna”.
msw
5
Ponieważ pomyślałem, że maksymalizacja mantysy da mi najwyższą możliwą do przedstawienia liczbę. 2 ^ 22. Nie, to pytanie z ciekawości. Zawsze czułem się winny umieszczając int w zmiennoprzecinkowych, nawet jeśli wiem, że dany int zawsze będzie bardzo mały. Chcę wiedzieć, jaka jest górna granica. O ile wiem, tytuł i pytanie są takie same, tylko inaczej sformułowane.
Floomi
1
@KyleStrand przywrócony ^ 2. Nie wiem, dlaczego jeden wydawał mi się bardziej poprawny niż drugi w tamtym czasie. Teraz oba wydają się niezręczne w porównaniu z „… to liczba bitów…”
Pascal Cuoq,

Odpowiedzi:

211

2 bity mantysy + 1 + 1

+1 w wykładniku (bity mantysy + 1) wynika z faktu, że jeśli mantysa zawiera abcdef...liczbę, którą reprezentuje, to w rzeczywistości 1.abcdef... × 2^ezapewnia dodatkowy ukryty bit precyzji.

Dlatego pierwszą liczbą całkowitą, której nie można dokładnie przedstawić i która zostanie zaokrąglona, ​​jest:
For float, 16,777,217 (2 24 + 1).
Dla double9,007,199,254,740,993 (2 53 + 1).

>>> 9007199254740993.0
9007199254740992
kennytm
źródło
Zadeklarowałem a floati ustawiłem go na 16,777,217. Ale kiedy go wydrukowałem, przy coutjego użyciu otrzymałem 16 777 216. Używam C++. Dlaczego nie mogę dostać 16,777,217?
azotan sodu
18
@sodiumnitrate Sprawdź tytuł pytania. 16777217 jest pierwszą liczbą całkowitą, której nie można dokładnie przedstawić.
kennytm
Ok dzięki. Byłem zdezorientowany, przepraszam za to. Mam jednak inne pytanie: czy po 16777216 następną liczbą całkowitą, którą można przedstawić, nie powinna być 2 * 16777216? Kiedy uruchamiam podobny program, otrzymuję 16777218, dodając 2 do 16777126.
sodu
5
Następna liczba całkowita to rzeczywiście 16777218, ponieważ 2 staje się teraz ostatnią znaczącą cyfrą binarną.
kennytm
6
W C ++ to (1 << std::numeric_limits<float>::digits) + 1, aw C (1 << FLT_MANT_DIG) + 1,. Pierwsza jest fajna, ponieważ może być częścią szablonu. Nie dodawaj +1, jeśli chcesz tylko największej reprezentowalnej liczby całkowitej.
Henry Schreiner
38

Największa wartość reprezentowana przez n- bitową liczbę całkowitą to 2 n -1. Jak wspomniano powyżej, a floatma 24 bity precyzji w znaczeniu, co wydaje się sugerować, że 2 24 nie będzie pasować.

Jednak .

Potęgi 2 w zakresie wykładnika są dokładnie reprezentowane jako 1,0 × 2 n , więc 2 24 mogą pasować, a zatem pierwsza nieprzedstawialna liczba całkowita dla floatto 2 24 +1. Jak wspomniano wyżej. Jeszcze raz.

tak powiedział ak
źródło
1
To jasno wyjaśniało część drugiego „dodatkowego ukrytego bitu precyzji”. Dzięki.
chappjc