Podczas konwersji z liczby całkowitej na pojedynczą może stracić precyzję

27

Czytałem artykuł z firmy Microsoft dotyczącą Poszerzenie konwersji i Option Strict On , gdy dostałem się do części

Następujące konwersje mogą stracić precyzję:

  • Integer to Single
  • Długi do pojedynczego lub podwójnego
  • Dziesiętny na pojedynczy lub podwójny

Jednak te konwersje nie tracą informacji ani wielkości.

.. ale zgodnie z innym artykułem dotyczącym typów danych ,

  • Typ liczby całkowitej może przechowywać od -2.147.483.648 do 2.147.483.647 i

  • Jeden typ może przechowywać od

    • Od 1,401298E-45 do 3,4028235E + 38 dla liczb dodatnich,
    • i -3,4028235E + 38 do - 1,401298E-45 dla liczb ujemnych

.. więc Single może przechowywać znacznie więcej liczb niż Integer. Nie mogłem zrozumieć, w jakiej sytuacji taka konwersja z Integer na Single może stracić precyzję. Czy mógłby ktoś wyjaśnić?

Winicjusz V.
źródło

Odpowiedzi:

87

Pojedynczy może przechowywać znacznie więcej liczb niż liczba całkowita

Nie, nie może. Zarówno Singlei Integerjest 32 bitów, co oznacza, że obydwa mogą przechowywać z dokładnie taką samą ilość cyfr, mianowicie 2 32 = 4294967296 różnych cyfr.

Ponieważ zakres od Singlejest wyraźnie większy niż, że jest to oczywiste (ze względu na zaszufladkować Principle ), że nie można ewentualnie reprezentują wszystkie numery w tym przedziale.

A ponieważ zakres Integerjest dokładnie tego samego rozmiaru co maksymalna liczba liczb, które oba mogą Integeri Singlereprezentować, ale Singlemogą również reprezentować liczby poza tym zakresem, jasne jest, że nie może reprezentować wszystkich liczb w zakresie Integer.

Jeśli istnieje kilka takich liczb Integer, których nie można przedstawić Single, konwersja z Integerna Single musi być zdolna do utraty informacji.

Jörg W Mittag
źródło
3
+1 za to świetne wyjaśnienie, dlaczego tak się dzieje, nawet jeśli pytanie brzmiało, kiedy („w jakiej sytuacji”) się zdarza…
dwukrotnie
21
@doubleYou: 4261412864 z 4294967296 Integers (99,2%) nie może być reprezentowany jako Single, więc „kiedy” jest „prawie zawsze”.
Jörg W Mittag
2
Jeśli chcesz być bardziej precyzyjny, Singlemoże reprezentować tylko 4 278 190 079 różnych liczb. SingleWartość reprezentuje numer wtedy i tylko wtedy, gdy przechowywane wykładnik od 255, co oznacza, że istnieje 255 * 2 ^ 24 Singles reprezentujące numery. Spośród nich dwa z nich reprezentują tę samą liczbę (mianowicie zero), a pozostałe wszystkie reprezentują różne liczby.
Tanner Swett
10
en.wikipedia.org/wiki/Single-precision_floating-point_format ładnie wyjaśnia ograniczenia dla IEEE754 binary32. Liczby całkowite w [-16777216,16777216](2 ^ 24 = znaczenie i szerokość) mogą być dokładnie przedstawione. Większe liczby są zaokrąglane do najbliższej wielokrotności 2, 4, 8, ... w zależności od ich wielkości.
Peter Cordes
14
„Co oznacza, że ​​oba mogą przechowywać dokładnie taką samą liczbę liczb” - to nie znaczy, że. Oznaczałoby to tylko, że jeśli oba typy mają dokładnie taką samą liczbę sposobów przechowywania każdej liczby. I tak nie jest; na przykład Singlema dwa sposoby przechowywania zera. SingleMoże więc w rzeczywistości reprezentować mniej wyraźnych liczb niż Integer.
Konrad Rudolph
28

Typy zmiennoprzecinkowe (takie jak Single i Double) są reprezentowane w pamięci przez znak, mantysę i wykładnik potęgi. Potraktuj to jako notację naukową:

Sign*Mantissa*Base^Exponent

Używają - jak można się spodziewać - podstawy 2. Istnieją inne poprawki, które pozwalają na reprezentowanie nieskończoności i NaN, a wykładnik jest przesunięty (wróci do tego), a stenografia dla mantysy (również do tego wróci) . Poszukaj standardu IEEE 754, który obejmuje jego reprezentację i operacje, aby uzyskać więcej szczegółów.

Dla naszych celów możemy sobie wyobrazić go jako liczbę binarną „mantysa” i „wykładnik”, który mówi ci, gdzie umieścić separator dziesiętny.


W przypadku singla mamy 1 bit na znak, 8 na wykładnik i 23 na mantysę.

Rzecz w tym, że będziemy przechowywać mantysę od najbardziej znaczącej cyfry. Pamiętaj, że wszystkie zera po lewej stronie nie są istotne. Biorąc pod uwagę, że pracujemy w trybie binarnym, wiemy, że najbardziej znaczącą cyfrą jest 1 ※. Skoro wiemy o tym, nie musimy go przechowywać. Dzięki temu skrótowi efektywny zasięg mantysy wynosi 24 bity.

※: Chyba że liczba, którą przechowujemy, wynosi zero. W tym celu wszystkie bity zostaną ustawione na zero. Jeśli jednak spróbujemy zinterpretować to pod podanym przeze mnie opisem, otrzymamy 2 ^ 24 (domyślną 1) pomnożoną przez 1 (2 do potęgi wykładnika 0). Tak więc, aby to naprawić, wykładnik zera jest wartością specjalną. Istnieją również specjalne wartości do przechowywania nieskończoności i NaN w wykładniku.

Zgodnie z przesunięciem wykładnika - oprócz unikania specjalnych wartości - przesunięcie pozwala na umieszczenie kropki dziesiętnej przed początkiem mantysy lub po jej zakończeniu, bez potrzeby posiadania znaku dla wykładnika.


Oznacza to, że w przypadku dużych liczb typ zmiennoprzecinkowy umieści przecinek dziesiętny poza końcem mantysy.

Pamiętaj, że mantysa jest liczbą 24-bitową. Nigdy nie będzie reprezentował 25-bitowej liczby ... nie ma tego dodatkowego bitu. Zatem singiel nie może rozróżnić między 2 ^ 24 a 2 ^ 24 + 1 (są to pierwsze 25 bitów, i różnią się w ostatnim bicie, który nie jest reprezentowany w singlu).

Zatem dla liczb całkowitych zasięg singla wynosi od -2 ^ 24 do 2 ^ 24. A próba dodania 1 do 2 ^ 24 spowoduje 2 ^ 24 (ponieważ jeśli chodzi o typ, 2 ^ 24 i 2 ^ 24 + 1 mają tę samą wartość). Wypróbuj online . Dlatego podczas konwersji z liczby całkowitej na liczbę pojedynczą występuje utrata informacji. I właśnie dlatego pętla, która korzysta z pojedynczego lub podwójnego, może być pętlą nieskończoną bez zauważenia.

Theraot
źródło
To nie jest doskonałe wyjaśnienie ukrytego 1bitu wiodącego w znaczeniu. Wynika to z faktu, że pole tendencyjnego wykładnika jest niezerowe . Subnormale (znane również jako denormale), w tym+-0.0 mają wiodący 0bit swojego znaczenia. Wydaje mi się, że można uprościć rozważenie 0.0całkowicie specjalnego przypadku, ale w 0.0rzeczywistości stosuje się te same reguły kodowania, co inne podnormale.
Peter Cordes
25

Oto rzeczywisty przykład konwersji z Integerna Singlemoże stracić precyzję:

SingleTypu może przechowywać wszystkie liczby całkowite od -16777216 do 16.777.216 (włącznie), ale nie można zapisać wszystkie liczby całkowite poza tym zakresem. Na przykład nie może przechowywać liczby 16777217. W tym przypadku nie może przechowywać żadnych liczb nieparzystych większych niż 16777216.

Możemy użyć Windows PowerShell, aby zobaczyć, co się stanie, jeśli przekonwertujemy Integerna Singleai wstecz:

PS C:\Users\tanne> [int][float]16777213
16777213
PS C:\Users\tanne> [int][float]16777214
16777214
PS C:\Users\tanne> [int][float]16777215
16777215
PS C:\Users\tanne> [int][float]16777216
16777216
PS C:\Users\tanne> [int][float]16777217
16777216
PS C:\Users\tanne> [int][float]16777218
16777218
PS C:\Users\tanne> [int][float]16777219
16777220

Zauważ, że 16777217 zaokrąglono w dół do 16777216, a 16777219 zaokrąglono w górę do 16777220.

Tanner Swett
źródło
4
A wraz ze wzrostem wielkości odległość między najbliższymi reprezentowalnymi floats stale rośnie jako potęgi. en.wikipedia.org/wiki/…
Peter Cordes
12

Typy zmiennoprzecinkowe są podobne do „notacji naukowej” w fizyce. Liczba jest podzielona na bit znaku, wykładnik potęgi (mnożnik) i mantysę (cyfry znaczące). Zatem wraz ze wzrostem wielkości wartość zwiększa się również rozmiar kroku.

Zmienny punkt zmienny o pojedynczej precyzji ma 23 bity mantysy, ale istnieje „domyślny 1”, więc mantysa ma w rzeczywistości 24 bity. Dlatego wszystkie liczby całkowite o wielkości do 2 24 mogą być przedstawione dokładnie w zmiennoprzecinkowym pojedynczej precyzji.

Powyżej tego mogą być reprezentowane kolejno mniejsze liczby.

  • Od 2 24 do 2 25 mogą być reprezentowane tylko liczby parzyste.
  • Od 2 25 do 2 26 mogą być reprezentowane tylko wielokrotności 4.
  • Od 2 26 do 2 27 mogą być reprezentowane tylko wielokrotności liczby 8.
  • Od 2 27 do 2 28 mogą być reprezentowane tylko wielokrotności 16
  • Od 2 28 do 2 29 może być reprezentowanych tylko wielokrotność 32
  • Od 2 29 do 2 30 może być reprezentowanych tylko wielokrotność 64
  • Od 2 30 do 2 31 mogą być reprezentowane tylko wielokrotności 128

Tak więc spośród 2 32 możliwych 32-bitowych liczb całkowitych ze znakiem tylko 2 * (2 24 + 7 * 2 23 ) = 9 * 2 24 może być reprezentowane w zmiennoprzecinkowym pojedynczej precyzji. To 3,515625% całości.

Peter Green
źródło
8

Pływaki pojedynczej precyzji mają 24 bity precyzji. Wszystko ponad to jest zaokrąglane do najbliższej liczby 24-bitowej. Może być łatwiejsze do zrozumienia w dziesiętnej notacji naukowej, ale należy pamiętać, że rzeczywiste zmiennoprzecinkowe używają plików binarnych.

Załóżmy, że masz 5 cyfr dziesiętnych pamięci. Możesz użyć takich jak zwykłe int bez znaku, co pozwala mieć dowolną liczbę od 0 do 99999. Jeśli chcesz być w stanie reprezentować większe liczby, możesz użyć notacji naukowej i po prostu przydzielić dwie cyfry jako wykładnik, więc możesz teraz reprezentować wszystko od 0 do 9,99 x 10 99 .

Jednak największa liczba, którą możesz dokładnie przedstawić, to teraz tylko 999. Jeśli próbujesz reprezentować 12345, możesz uzyskać 1,23 x 10 4 lub 1,24 x 10 4 , ale nie możesz reprezentować żadnej z liczb pośrednich, ponieważ nie ma wystarczającej liczby dostępnych cyfr.

Karl Bielefeldt
źródło
3
Korzystanie cyfry dziesiętne to pomysł ładny sprawia, że łatwiej jest zrozumieć, ale ostatni akapit jest nieco mylący: rzeczywiście jesteś może reprezentować liczby wyższej niż 999, a Twoje przykład pokazuje go: 12300 byłoby 1,23 x 10 <sup> 4 <sup >. Chodzi ci o to, że zaczynając od tej liczby są luki. Czy miałbyś coś przeciwko przeredagowaniu?
Fabio mówi Przywróć Monikę