Komputery mają problemy z przechowywaniem liczb ułamkowych, w których mianownik jest czymś innym niż rozwiązaniem 2 ^ x. Jest tak, ponieważ pierwsza cyfra po przecinku jest warta 1/2, druga 1/4 (lub 1 / (2 ^ 1) i 1 / (2 ^ 2)) itp.
Po co radzić sobie z różnego rodzaju błędami zaokrąglania, gdy komputer mógł właśnie zapisać dziesiętną część liczby jako kolejną liczbę całkowitą (która jest zatem dokładna?)
Jedyne, co mogę wymyślić, to radzenie sobie z powtarzaniem miejsc po przecinku (w bazie 10), ale mogło być rozwiązanie skrajne (tak jak obecnie mamy nieskończoność).
numbers
numeric-precision
SomeKittens
źródło
źródło
Odpowiedzi:
Istnieją w rzeczywistości tryby liczb, które to robią.
Arytmetyka dziesiętna (BCD) dziesiętna (BCD) powoduje, że komputer działa w bazie 10. Powodem, dla którego tak rzadko się zdarza, jest to, że marnuje miejsce: każda pojedyncza cyfra liczby zajmuje minimum cztery bity, podczas gdy komputer mógłby przechowywać do 16 wartości w tej przestrzeni. (Może być również wolniejszy, ale możliwe jest, że matematyka BCD z akceleracją sprzętową działa dobrze). To właśnie robi większość kalkulatorów, dlatego istnieją pewne klasy problemów z zaokrąglaniem, których nigdy nie trafisz na Casio za 5 USD, które zje lunch na komputerze stacjonarnym.
Inną drogą, którą możesz wybrać, jest użycie liczb wymiernych - to znaczy licznika i mianownika, zapisanych jako liczby całkowite. Jest to faktycznie dostępne w prawie wszystkich językach, jest dokładne i pozwala przechowywać wszystko w natywnych formatach binarnych. Problem polega na tym, że na koniec użytkownicy prawdopodobnie nie chcą widzieć ułamków takich jak 463/13, a nawet 35 i 8/13. Chcą zobaczyć 35,155 ... a gdy tam dotrzesz, napotkasz wszystkie typowe problemy. Dodaj, że ten format zajmuje jeszcze więcej miejsca i może być znacznie wolniejszy niż arytmetyka zmiennoprzecinkowa, a domyślnie żaden komputer nie używa tego formatu.
Tak więc: komputery mogą robić, co chcesz, ale są wolne i marnują miejsce, więc robią to tylko wtedy, gdy naprawdę muszą. Reszta czasu, szybkość i oszczędność miejsca zmiennoprzecinkowego są lepszym kompromisem.
źródło
decimal
implementacji języka C # : stackoverflow.com/a/5019178/174335 To nie jest BCD, ponieważ nie ma indywidualnej reprezentacji cyfr dziesiętnych i nie jest stałym punktem.Istnieje wiele sposobów przechowywania liczb ułamkowych, a każdy z nich ma zalety i wady.
Punkt zmiennoprzecinkowy jest zdecydowanie najpopularniejszym formatem. Działa poprzez kodowanie znaku, mantysy i podpisanego wykładnika wykładnika base-2 w liczbach całkowitych i upakowanie ich w wiązkę bitów. Na przykład, możesz mieć 32-bitową mantysę
0.5
(zakodowaną jako0x88888888
) i 32-bitowy wykładnik wykładniczy+3
(0x00000003
), który dekodowałby do4.0
(0.5 * 2 ^ 3
). Liczby zmiennoprzecinkowe są szybkie, ponieważ są implementowane sprzętowo, a ich precyzja skaluje się z rozmiarem bezwzględnym, to znaczy im mniejsza liczba, tym lepsza jest twoja absolutna precyzja, więc względny błąd zaokrąglenia pozostaje stały przy wielkości bezwzględnej. Pływaki są doskonałe dla wartości próbkowanych z ciągłej dziedziny, takich jak długości, poziomy ciśnienia akustycznego, poziomy światła itp. Z tego powodu są one powszechnie stosowane w przetwarzaniu dźwięku i obrazu, a także w analizach statystycznych i symulacjach fizycznych. Ich największą wadą jest to, że nie są dokładne, to znaczy są podatne na błędy zaokrąglania i nie mogą dokładnie przedstawić wszystkich ułamków dziesiętnych. Wszystkie języki programowania głównego nurtu mają pewnego rodzaju zmiennoprzecinkowe.Punkt stałydziała, używając wystarczająco dużych liczb całkowitych i niejawnie rezerwując część swoich bitów na część ułamkową. Na przykład 24,8-bitowa liczba stałoprzecinkowa rezerwuje 24 bity dla części całkowitej (łącznie ze znakiem) i 8 bitów dla części ułamkowej. Przesunięcie w prawo tej liczby o 8 bitów daje nam liczbę całkowitą. Numery stałoprzecinkowe były popularne, gdy sprzętowe jednostki zmiennoprzecinkowe były rzadkie lub co najmniej znacznie wolniejsze niż ich odpowiedniki liczb całkowitych. Chociaż liczby stałoprzecinkowe są nieco łatwiejsze do obsługi pod względem dokładności (choćby dlatego, że łatwiej je zrozumieć), są gorsze od liczb zmiennoprzecinkowych pod każdym innym względem - mają mniejszą precyzję, mniejszy zakres i ponieważ dodatkowe potrzebne są operacje, aby skorygować obliczenia dla niejawnego przesunięcia, matematyka stałoprzecinkowa jest dziś często wolniejsza niż matematyka zmiennoprzecinkowa.
Typy dziesiętne działają podobnie do liczb zmiennoprzecinkowych lub liczb stałych, ale przyjmują układ dziesiętny, to znaczy, że ich wykładnik (niejawny lub jawny) koduje potęgę-10, a nie potęgę-2. Liczba dziesiętna może na przykład zakodować mantysę
23456
i wykładnik wykładni-2
, a to rozszerzy się do234.56
. Dziesiętne, ponieważ arytmetyka nie jest wbudowana w procesor, są wolniejsze niż zmiennoprzecinkowe, ale idealnie nadają się do wszystkiego, co wymaga liczb dziesiętnych i wymaga, aby te liczby były dokładne, z zaokrąglaniem występującym w dobrze określonych miejscach - obliczenia finansowe, tablice wyników itp. Niektóre języki programowania mają wbudowane typy dziesiętne (np. C #), inne wymagają bibliotek do ich implementacji. Zauważ, że chociaż dziesiętne mogą dokładnie reprezentować nie powtarzające się ułamki dziesiętne, ich dokładność nie jest lepsza niż w przypadku liczb zmiennoprzecinkowych; wybranie liczb dziesiętnych oznacza po prostu uzyskanie dokładnych reprezentacji liczb, które mogą być reprezentowane dokładnie w systemie dziesiętnym (podobnie jak zmienne mogą dokładnie reprezentować ułamki binarne).Liczby wymierne przechowują licznik i denumerator, zwykle przy użyciu pewnego rodzaju liczb całkowitych bignum (typ liczbowy, który może rosnąć tak duże, jak pozwalają na to ograniczenia pamięci komputera). Jest to jedyny typ danych z grupy, który może dokładnie modelować liczby takie jak
1/3
lub3/17
, a także operacje na nich - racjonalne, w przeciwieństwie do innych typów danych, będą dawać poprawne wyniki dla rzeczy takich jak3 * 1/3
. Matematyka jest dość prosta, choć wymyślenie wydajnego algorytmu faktoringowego jest dość trudne. Niektóre języki programowania mają wbudowane racjonalne typy (np. Common Lisp). Wady racjonalności obejmują to, że są one powolne (wiele operacji wymaga zmniejszenia ułamków i faktoryzacji ich komponentów) oraz że wiele typowych operacji jest trudnych lub niemożliwych do wdrożenia, a większość implementacji zdegraduje racjonalność do liczby zmiennoprzecinkowej, gdy to nastąpi (np. Gdy wywołujeszsin()
racjonalny).BCD (Binary Coded Decimal) wykorzystuje „skubki” (grupy 4 bitów) do kodowania poszczególnych cyfr; ponieważ skrobak może pomieścić 16 różnych wartości, ale liczby dziesiętne wymagają tylko 10, istnieje 6 „nielegalnych” wartości na skubanie. Podobnie jak ułamki dziesiętne, liczby BCD są dokładne dziesiętnie, to znaczy obliczenia wykonywane na liczbach dziesiętnych działają tak samo, jak gdyby były zrobione za pomocą pióra i papieru. Reguły arytmetyczne dla BCD są nieco niezdarne, ale zaletą jest to, że konwersja ich na ciągi znaków jest łatwiejsza niż w przypadku niektórych innych formatów, co jest szczególnie interesujące w środowiskach o niskim zużyciu zasobów, takich jak systemy osadzone.
Ciągi , tak, zwykłe stare ciągi, mogą być również użyte do przedstawienia liczb ułamkowych. Technicznie jest to bardzo podobne do BCD, tyle że istnieje wyraźna kropka dziesiętna i używasz jednego pełnego bajtu na cyfrę dziesiętną. W związku z tym format jest marnotrawny (używanych jest tylko 11 z 256 możliwych wartości), ale łatwiej go analizować i generować niż BCD. Dodatkowo, ponieważ wszystkie użyte wartości są „niepomyślne”, nieszkodliwe i neutralne dla platformy, liczby zakodowane w łańcuchach mogą bez problemu podróżować po sieci. Rzadko zdarza się, aby arytmetyka była wykonywana bezpośrednio na ciągach, ale jest to możliwe, a gdy to zrobisz, są one tak samo dokładne dziesiętnie jak inne formaty dziesiętne (dziesiętne i BCD).
źródło
Liczby zmiennoprzecinkowe reprezentują szeroki zakres wartości, co jest bardzo przydatne, gdy nie wiesz z góry, jakie mogą być wartości, ale jest to kompromis. Reprezentowanie 1/10 ^ 100 z drugą liczbą całkowitą nie działałoby.
Niektóre języki (i niektóre biblioteki) mają inne cechy. Lisp tradycyjnie ma nieskończoną liczbę całkowitą precyzji. Cobol ma obliczenia z liczbami stałymi dziesiętnymi.
Musisz wybrać reprezentację numeru odpowiednią dla domeny problemu.
źródło
Brzmi, jakbyś opisywał liczby w punktach stałych .
Należy pamiętać, że przechowywanie części ułamkowej liczby w oddzielnym miejscu jest dokładnie identyczne z tworzeniem pojedynczej przestrzeni, dwa razy większej, i przechowywaniem całej i części ułamkowej w dwóch oddzielnych połówkach. Innymi słowy, jest to identyczne z przechowywaniem liczby jako liczby całkowitej, ale po prostu zakłada stałą liczbę miejsc dziesiętnych.
Zwykle liczby zmiennoprzecinkowe są przechowywane przy użyciu wariacji binarnej w notacji naukowej, ponieważ zwykle ważne są cyfry znaczące. Istnieje jednak wiele innych metod. Liczby dziesiętne o stałym punkcie są powszechnie stosowane, na przykład do przechowywania wartości walutowych, gdzie dokładność jest krytyczna do określonej liczby miejsc po przecinku, ale liczba wymaganych cyfr po przecinku nigdy się nie zmienia.
źródło
To by się nazywało BCD, myślę, że nadal możesz go używać, jeśli naprawdę chcesz. Jednak nie jest to warte tego, ponieważ:
źródło
Krótka odpowiedź jest taka, że zmiennoprzecinkowy został zaprojektowany do obliczeń naukowych. Może przechowywać liczbę z (do) określoną liczbą cyfr znaczących, co ściśle pasuje do sposobu pomiaru precyzji w większości obliczeń naukowych.
Jest to zwykle obsługiwane głównie przez sprzęt, ponieważ obliczenia naukowe zwykle były tymi, które najbardziej skorzystały na wsparciu sprzętowym. Na przykład, obliczenia finansowe są często wykonywane w innych formatach - ale oprogramowanie finansowe zwykle wykonuje mało rzeczywistych obliczeń, które mimo że niezbędne formaty są obsługiwane tylko w oprogramowaniu, wydajność pozostaje całkowicie wystarczająca dla większości programów finansowych.
źródło