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ą jako 0x88888888
) i 32-bitowy wykładnik wykładniczy +3
( 0x00000003
), który dekodowałby do 4.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
lub 3/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łujesz sin()
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).