Liczba zmiennoprzecinkowa


Liczba zmiennoprzecinkowa w encyklopedii

Z Wikipedii, wolnej encyklopedii Przejdź do nawigacji Przejdź do wyszukiwania

Liczba zmiennoprzecinkowa – reprezentacja liczby rzeczywistej zapisanej za pomocą notacji naukowej. Ze względu na wygodę operowania na takich liczbach, przyjmuje się ograniczony zakres na mantysę i cechę – nazwy te mają w matematyce znaczenie podane w artykule podłoga i sufit, a w niniejszym artykule inne, powszechne w informatyce. Powoduje to, że reprezentacja liczby rzeczywistej jest tylko przybliżona, a jedna liczba zmiennoprzecinkowa może reprezentować różne liczby rzeczywiste z pewnego zakresu.

Spis treści

Podstawa matematyczna | edytuj kod

Wartość liczby zmiennoprzecinkowej jest obliczana według wzoru:

x = S M B E , {\displaystyle x=SMB^{E},}

gdzie:

S {\displaystyle S} (ang. sign) – znak liczby, 1 lub −1, M {\displaystyle M} (ang. mantissa) – znormalizowana mantysa, liczba ułamkowa[1], B {\displaystyle B} (ang. base) – podstawa systemu liczbowego[1] (2 dla systemów komputerowych), E {\displaystyle E} (ang. exponent) – wykładnik, cecha, liczba całkowita[1].

Mantysa jest znormalizowana, tj. należy do przedziału 1 , B ) {\displaystyle [1,B)} (przedział prawostronnie otwarty!). Jeżeli M {\displaystyle M} jest stałe, a E {\displaystyle E} zmienia się, wówczas przesunięciu ulega przecinek – stąd właśnie pochodzi nazwa tej reprezentacji.

Zarówno dla mantysy, jak i wykładnika liczba cyfr jest z góry ustalona. Zatem dana liczba jest reprezentowana z pewną skończoną dokładnością i należy do skończonego zbioru wartości[2].

Załóżmy, że m {\displaystyle m} to liczba cyfr przeznaczonych na mantysę, natomiast n + 1 {\displaystyle n+1} to liczba cyfr przeznaczonych na wykładnik ( n {\displaystyle n} cyfr dla wartości i 1 dla znaku wykładnika). Uznaje się również, że jedna dodatkowa pozycja (najstarsza) zarezerwowana jest dla zapisu znaku całej liczby. Wówczas wartości maksymalne i minimalne dla M {\displaystyle M} i E {\displaystyle E} określone są następująco:

  • Wykładnik E : {\displaystyle E{:}}
    • E min = B n + 1 , {\displaystyle E_{\min }=-B^{n}+1,}
    • E max = B n 1. {\displaystyle E_{\max }=B^{n}-1.}
  • Mantysa M : {\displaystyle M{:}}
    • M min = 1 , {\displaystyle M_{\min }=1,}
    • M max = B B ( m 1 ) . {\displaystyle M_{\max }=B-B^{-(m-1)}.}

Stąd najmniejsza i największa liczba dodatnia możliwa do zapisania w takiej reprezentacji to:

  • x min = M min B E min = 1 B E m i n , {\displaystyle x_{\min }=M_{\min }B^{E_{\min }}=1\cdot B^{E_{min}},}
  • x max = M max B E max = ( B B ( m 1 ) ) B E m a x < B E m a x + 1 . {\displaystyle x_{\max }=M_{\max }B^{E_{\max }}=\left(B-B^{-(m-1)}\right)B^{E_{max}}<B^{E_{max}+1}.}

Zakres liczb, które mogą być reprezentowane w danym zapisie wynosi:

x max , x min { 0 } x min , x max . {\displaystyle [-x_{\max },-x_{\min }]\cup \{0\}\cup [x_{\min },x_{\max }].}

Zero jest wartością specjalną, która nie może zostać bezpośrednio reprezentowana w tym formacie.

Błąd względny reprezentacji wynosi 1 2 B m 1 {\displaystyle {\frac {1}{2B^{m-1}}}} (inaczej: połowa wagi najmniej znaczącej cyfry mantysy). Błędów bezwzględnych na ogół się nie podaje.

Jeżeli komputer wygeneruje liczbę | x | < B E min , {\displaystyle |x|<B^{E_{\min }},} to traktowana jest jako niedomiar (underflow).

W przypadku, gdy otrzymana liczba | x | > M max B E max , {\displaystyle |x|>M_{\max }B^{E_{\max }},} to traktowana jest jako nadmiar wykładniczy (overflow).

Przykład reprezentacji | edytuj kod

Przyjmijmy, że B = 10 , {\displaystyle B=10,} liczba cyfr dziesiętnych przeznaczonych na mantysę wynosi 4, natomiast na wykładnik 2. Chcemy zapisać wartość 60,895 23. {\displaystyle 60{,}89523.}

Liczba 60,895 23 {\displaystyle 60{,}89523} odpowiada M = 60,895 23 , E = 0. {\displaystyle M=60{,}89523,E=0.}

Normalizacja mantysy:

Mantysa nie należy do przedziału 1 , 10 ) , {\displaystyle [1,10),} zatem należy przesuwać przecinek w lewo aż będzie doń należała. Przesuwanie przecinka w lewo wiąże się ze zwiększaniem wykładnika. M = 6,089 523 , E = 1. {\displaystyle M=6{,}089523,E=1.}

Odcięcie i zaokrąglenie mantysy:

po odcięciu: 6,089 , {\displaystyle 6{,}089,} po zaokrągleniu: 6,090. {\displaystyle 6{,}090.}

Wynik:

6,090 10 1 = 6 , 09 , E = 1. {\displaystyle 6{,}090\cdot 10^{1}=6{,}09,E=1.}

Przykład dla liczby mniejszej od 1: 0,000 0125. {\displaystyle 0{,}0000125.}

M = 0,000 0125 , E = 0. {\displaystyle M=0{,}0000125,E=0.}

Po normalizacji:

M = 1 , 25 , E = 5. {\displaystyle M=1{,}25,E=-5.}

Liczba cyfr znaczących jest mniejsza od dostępnej, więc nie jest potrzebne zaokrąglanie.

Wynik:

1,250 10 5 = 1 , 25 , E = 5. {\displaystyle 1{,}250\cdot 10^{-5}=1{,}25,E=-5.}

Operacje na liczbach zmiennoprzecinkowych | edytuj kod

Własności arytmetyki zmiennoprzecinkowej | edytuj kod

Arytmetyka zmiennoprzecinkowa nie jest łączna. To znaczy, że dla x , {\displaystyle x,} y {\displaystyle y} i z {\displaystyle z} mogą zachodzić różności:

  • ( x + y ) + z x + ( y + z ) , {\displaystyle (x+y)+z\neq x+(y+z),}
  • ( x y ) z x ( y z ) . {\displaystyle (xy)z\neq x(yz).}

Nie jest też rozdzielna, czyli może zachodzić różność:

  • x ( y + z ) ( x y ) + ( x z ) . {\displaystyle x(y+z)\neq (xy)+(xz).}

Innymi słowy, kolejność wykonywania operacji wpływa na końcowy wynik.

Przy obliczeniach zmiennoprzecinkowych występują też:

  • zaokrąglenia,
  • nieprawidłowe operacje,
  • przepełnienie,
  • niedomiar.

Dodawanie i odejmowanie | edytuj kod

Załóżmy że chcemy dodać lub odjąć dwie dodatnie liczby zmiennoprzecinkowe: x 1 = M 1 B E 1 {\displaystyle x_{1}=M_{1}B^{E_{1}}} oraz x 2 = M 2 B E 2 , {\displaystyle x_{2}=M_{2}B^{E_{2}},} przy czym x 1 x 2 . {\displaystyle x_{1}\geqslant x_{2}.} Założenia te można spełnić dla dowolnych liczb zmiennoprzecinkowych, manipulując ich kolejnością, znakiem wyniku oraz rodzajem wykonywanej operacji, według poniższego schematu:

( + x 1 ) + ( + x 2 ) , ( + x 1 ) ( x 2 ) , ( + x 2 ) + ( + x 1 ) , ( + x 2 ) ( x 1 ) + ( x 1 + x 2 ) , ( + x 1 ) + ( x 2 ) , ( + x 1 ) ( + x 2 ) , ( x 2 ) + ( + x 1 ) , ( x 2 ) ( x 1 ) + ( x 1 x 2 ) , ( x 1 ) + ( x 2 ) , ( x 1 ) ( + x 2 ) , ( x 2 ) + ( x 1 ) , ( x 2 ) ( + x 1 ) ( x 1 + x 2 ) , ( x 1 ) + ( + x 2 ) , ( x 1 ) ( x 2 ) , ( + x 2 ) + ( x 1 ) , ( + x 2 ) ( + x 1 ) ( x 1 x 2 ) . {\displaystyle {\begin{matrix}(+x_{1})+(+x_{2}),&(+x_{1})-(-x_{2}),&(+x_{2})+(+x_{1}),&(+x_{2})-(-x_{1})&\to &+(x_{1}+x_{2}),\\(+x_{1})+(-x_{2}),&(+x_{1})-(+x_{2}),&(-x_{2})+(+x_{1}),&(-x_{2})-(-x_{1})&\to &+(x_{1}-x_{2}),\\(-x_{1})+(-x_{2}),&(-x_{1})-(+x_{2}),&(-x_{2})+(-x_{1}),&(-x_{2})-(+x_{1})&\to &-(x_{1}+x_{2}),\\(-x_{1})+(+x_{2}),&(-x_{1})-(-x_{2}),&(+x_{2})+(-x_{1}),&(+x_{2})-(+x_{1})&\to &-(x_{1}-x_{2}).\end{matrix}}}

Wówczas:

x 1 ± x 2 = ( M 1 ± M 2 B E 2 E 1 ) B E 1 . {\displaystyle x_{1}\pm x_{2}=(M_{1}\pm M_{2}B^{E_{2}-E_{1}})B^{E_{1}}.}

Jeśli liczby mają różne wykładniki, to podczas dodawania mantysa liczby o mniejszym wykładniku musi zostać zdenormalizowana – we wzorze jest to przemnożenie M 2 {\displaystyle M_{2}} przez czynnik B E 2 E 1 . {\displaystyle B^{E_{2}-E_{1}}.} W szczególnym przypadku, jeśli E 1 E 2 {\displaystyle E_{1}-E_{2}} jest większe niż m {\displaystyle m} (liczba cyfr mantysy), to po denormalizacji mantysa będzie miała wartość 0, a liczba o mniejszym wykładniku nie wpłynie na wynik dodawania bądź odejmowania.

Odejmowanie liczb zmiennoprzecinkowych o takim samym wykładniku E {\displaystyle E} i niewiele różniącej się mantysie powoduje, że wynikowa mantysa jest znacznie zdenormalizowana. Renormalizacja w takim wypadku wiąże się z wprowadzeniem sporej liczby nieznaczących zer na końcu mantysy. Jest to szczególnie niekorzystne, dlatego zwykle tak projektuje się obliczenia, by do tego nie dopuścić.

Mnożenie i dzielenie | edytuj kod

Mając dane liczby zmiennoprzecinkowe x 1 = S 1 M 1 B E 1 {\displaystyle x_{1}=S_{1}M_{1}B^{E_{1}}} i x 2 = S 2 M 2 B E 2 : {\displaystyle x_{2}=S_{2}M_{2}B^{E_{2}}{:}}

x 1 x 2 = ( S 1 S 2 ) ( M 1 M 2 ) B E 1 + E 2 , {\displaystyle x_{1}x_{2}=(S_{1}S_{2})(M_{1}M_{2})B^{E_{1}+E_{2}},} x 1 / x 2 = ( S 1 S 2 ) ( M 1 / M 2 ) B E 1 E 2 . {\displaystyle x_{1}/x_{2}=(S_{1}S_{2})(M_{1}/M_{2})B^{E_{1}-E_{2}}.}

Błędy operacji elementarnych | edytuj kod

Wygodnie jest przedstawić liczbę zmiennoprzecinkową jako wartość dokładną zaburzoną pewnym błędem reprezentacji ε : {\displaystyle \varepsilon {:}}

x ¯ = x ( 1 + ε x ) {\displaystyle {\overline {x}}=x(1+\varepsilon _{x})}

Wówczas błąd względny poszczególnych operacji elementarnych wykonywanych na liczbach a ¯ = a ( 1 + ε a ) {\displaystyle {\overline {a}}=a(1+\varepsilon _{a})} oraz b ¯ = b ( 1 + ε b ) {\displaystyle {\overline {b}}=b(1+\varepsilon _{b})} można oszacować następująco:

  • dodawanie/odejmowanie: ε a ± b = a ε a ± b ε b a ± b + ε ± {\displaystyle \varepsilon _{a\pm b}={\frac {a\varepsilon _{a}\pm b\varepsilon _{b}}{a\pm b}}+\varepsilon _{\pm }}
  • mnożenie: ε a b = ε a + ε b + ε {\displaystyle \varepsilon _{ab}=\varepsilon _{a}+\varepsilon _{b}+\varepsilon _{\cdot }}
  • dzielenie: ε a / b = ε a ε b + ε / {\displaystyle \varepsilon _{a/b}=\varepsilon _{a}-\varepsilon _{b}+\varepsilon _{/}}

gdzie ε ± , {\displaystyle \varepsilon _{\pm },} ε {\displaystyle \varepsilon _{\cdot }} i ε / {\displaystyle \varepsilon _{/}} to błędy wprowadzane przez dane operacje arytmetyczne.

Rozbijając każde wyrażenie arytmetyczne na operacje elementarne, można za pomocą tych zależności oszacować powstałe błędy. Istnieją jednak lepsze i szybsze metody modelowania błędów.

Implementacje sprzętowe | edytuj kod

Reprezentacja zmiennoprzecinkowa IEEE-754 single

W implementacjach sprzętowych liczby zmiennoprzecinkowe wyraża się liczbami dwójkowymi (B = 2). Ma to następujące zalety:

  1. Mantysa należy do przedziału 1 , 2 ) , {\displaystyle [1,2),} jest więc postaci 1.xxxxx.... (gdzie x – bit o dowolnej wartości). Ponieważ część całkowita jest znana i równa zawsze 1, przeto nie jest zapamiętywana, co daje dodatkowy bit na część ułamkową.
  2. Ponieważ znak liczby jest zapamiętywany na jednym bicie, przeto otrzymanie modułu lub wartości przeciwnej wymaga, odpowiednio, wyzerowania tego bitu (logiczna operacja AND), lub zmiany na wartość przeciwną (logiczna operacja XOR).

W celu ujednolicenia zasad operacji na liczbach zmiennoprzecinkowych na różnych platformach sprzętowych, opracowano standard IEEE 754, w oparciu o który realizuje się obecnie wszystkie implementacje sprzętowe liczb zmiennoprzecinkowych. Definiuje on dwie klasy liczb:

  • pojedynczej precyzji (ang. single, single precision),
  • podwójnej precyzji (ang. double, double precision).

Są również inne sposoby zapisu, różniące się jedynie liczbą bitów przeznaczoną na poszczególne pola. Np. koprocesor w procesorach x86, oprócz typów standardowych, wspiera sprzętowo liczby 10-bajtowe, natomiast kompilator Pascala – w sposób programowy liczby 6-bajtowe[a]. Liczby zgodne ze standardem IEEE 754 mają dokładnie określoną semantykę, jak na przykład: dokładność operacji elementarnych, kierunki zaokrągleń czy obsługa sytuacji wyjątkowych – są to cechy bardzo pożądane w zastosowaniach naukowych i inżynieryjnych, a ponadto ułatwiają przenoszenie kodu programu na inną platformę sprzętową.

Przesunięcie wykładnika | edytuj kod

Wykładnik będący liczbą całkowitą jest zapisywany w kodzie spolaryzowanym, co można interpretować jako wartość przesuniętą o pewną stałą (ang. biased exponent). Właściwą wartość wykładnika uzyskuje się, odejmując od zakodowanego wykładnika wartość przesunięcia (ang. bias). Wartość liczby zmiennoprzecinkowej oblicza się ze wzoru:

x = ( 1 ) S M 2 E bias , {\displaystyle x=(-1)^{S}M\cdot 2^{E-{\textrm {bias}}},}

gdzie S {\displaystyle S} to bit znaku; liczba jest ujemna, gdy bit znaku jest równy 1, w przeciwnej sytuacji ma on wartość 0.

Typowe wartości przesunięcia dla koprocesora x87 (występującego w procesorach x86) wynoszą:

  • 127 (7Fh) w formacie 32-bitowym,
  • 1023 (3FFh) w formacie 64-bitowym,
  • 16383 (3FFFh) w formacie 80-bitowym.

Wartości specjalne | edytuj kod

Oprócz zwykłych liczb zdefiniowano następujące wartości specjalne:

  • NaN – nie-liczba (ang. Not-a-Number), to symbol, który nie reprezentuje wartości liczbowej, powstały zazwyczaj w wyniku niedozwolonej operacji (np. pierwiastkowanie liczby ujemnej)
    • sNaN – sygnalizujące NaN (ang. signalling NaN) – rozróżnienie wprowadzone w procesorach z rodziny x86; w większości przypadków wykonanie działania liczba operacja sNaN spowoduje zgłoszenie wyjątku.
    • qNaN – ciche NaN (ang. quiet NaN) – przekazanie tej wartości jako argumentu operacji nie powoduje zgłoszenia wyjątku; w operacjach SSE można ustalić, że liczba operacja qNaN → 0.
  • Zero – rozróżnia się +0,0 i -0,0.
  • Nieskończoność – jest wynikiem operacji w przypadku wystąpienia nadmiaru (przepełnienia), przy dzieleniu przez 0 itp.; może być dodatnia lub ujemna.
  • Liczba nieznormalizowana – pojawia się, gdy występuje niedomiar (ang. underflow), ale wynik operacji jeszcze można zapisać, denormalizując mantysę (w takim przypadku mantysa reprezentuje liczbę w postaci 0,xxx...xxx, a nie 1,xxx...xxxx). Wszystkie bity wykładnika są równe 0 i
x = ( 1 ) S M 2 bias + 1 {\displaystyle x=(-1)^{S}M\cdot 2^{-{\textrm {bias}}+1}}

Typy zmiennoprzecinkowe w językach programowania | edytuj kod

C, C++ | edytuj kod

Rozmiar typów zmiennoprzecinkowych zależy od konkretnych implementacji. Standardowo, typ float zajmuje co najmniej 4 bajty, double 8 bajtów, a long double zazwyczaj 8-16 bajtów. W przypadku kompilatora GCC w wersji 4.6.2, długości typów wynoszą odpowiednio 4, 8 i 16 bajtów, a w Visual C++ – 4, 8 i 8 bajtów.

Pascal | edytuj kod

W standardzie języka Pascal ISO/IEC 7185 :1990 jest wymagany typ real obejmujący podzbiór liczb rzeczywistych. Turbo Pascal wykorzystuje cztery typy zmiennoprzecinkowe (typ, liczba bajtów, liczba cyfr znaczących, zakres wartości):

  • single, 4 B, 7-8 cyfr, 1.5·10−45..3.4·1038[3]
  • real, 6 B, 11-12 cyfr, 2.9·10−39..1.7·1038[3]
  • double, 8 B, 15-16 cyfr, 5.0·10−324..1.7·10308[3]
  • extended, 10 B, 19-20 cyfr, 3.4·10−4932..1.1·104932[5]

Delphi obsługuje te same typy, przy czym w domyślnych ustawieniach opcji kompilatora typ real jest równoważny typowi double, a sześciobajtowy nazwano real48. We free Pascalu typ real jest zastępowany przez single lub double.

Fortran | edytuj kod

W oryginalnej specyfikacji języka Fortran typ real miał dwie możliwe długości REAL i DOUBLE PRECISION. Zakres i precyzja obydwu typów nie były wyspecyfikowane, lecz zależały od architektury konkretnego komputera, z wymaganiem aby DOUBLE PRECISION miał wyższą precyzję i co najmniej taki sam zakres co REAL.

Z czasem rynek został całkowicie zdominowany przez komputery o architekturze opartej na 8-bitowych bajtach, przyjęło się, że podstawowy typ REAL zajmuje 4 bajty. Współczesne kompilatory Fortranu dopuszczają deklaracje:

  • REAL*4 lub po prostu REAL – 32 bity, odpowiednik typu float w języku C
  • REAL*8 lub DOUBLE PRECISION – 64 bity, odpowiednik typu double w języku C

Niektóre implementacje dopuszczają także typ:

  • REAL*16 – 128 bitów.

Nowsze specyfikacje języka Fortran, poczynając od Fortran90, umożliwiają programiście deklarowanie wymaganej precyzji i zakresu liczb zmiennoprzecinkowych w oderwaniu od konkretnej implementacji. Wbudowana funkcja SELECTED_REAL_KIND(p,r) zwraca najkrótszą, dla konkretnego procesora, reprezentację o co najmniej wskazanej dokładności i zakresie. Na przykład SELECTED_REAL_KIND(10,80) zwróci dla danego procesora typ liczby zmiennoprzecinkowej o dokładności co najmniej 10 cyfr znaczących i zakresie co najmniej do 1080. Istnieją też wbudowane funkcje PRECISION i RANGE pozwalające sprawdzić jaki rzeczywisty zakres i dokładność mają liczby zmiennoprzecinkowe podanego typu w danym procesorze[6].

Kalkulator | edytuj kod

Sposoby wyświetlania liczb zmiennoprzecinkowych:

  • FLO (Floating Notation) – notacja dziesiętna – tryb domyślny. Jeżeli jest to możliwe wyświetla liczbę z wykładnikiem równym 0, pomijając jego wyświetlanie,
  • SCE (Scientific Notation) – notacja naukowa – zawsze wyświetla liczbę z wykładnikiem,
  • ENG (Engineering Notation) – notacja inżynierska – zawsze wyświetla liczbę z wykładnikiem podzielnym przez 3.

Historia | edytuj kod

Binarne liczby zmiennoprzecinkowe po raz pierwszy zastosował Konrad Zuse w mechanicznym komputerze Z1.

Zobacz też | edytuj kod

Uwagi | edytuj kod

  1. Firma Borland w kompilatorach języka Pascal począwszy od wersji Delphi 3.0 przyjęła za standard liczb zmiennoprzecinkowych liczby typu double, a stary typ został nazwany real48 i jest obsługiwany w celu zachowania zgodności z poprzednimi wersjami, ale ma status przestarzałego elementu języka, który w pewnym momencie może przestać być obsługiwany.

Przypisy | edytuj kod

  1. a b c Fortuna, Macukow i Wąsowski 1993 ↓, s. 10.
  2. Jankowski 1990 ↓, s. 92.
  3. a b c d Marciniak 1991 ↓, s. 539.
  4. Specyfikacja OpenGL 3.0, wersja z 11.08.2008, sekcja 2.1.2 „16-Bit Floating Point Number”.
  5. Marciniak 1991 ↓, s. 539–540.
  6. Michael Metcalf, John Ker Reid, Malcolm Cohen: Fortran 95/2003 explained. Oxford: Oxford University Press, 2004, s. 16. ISBN 978-0-19-852693-3.

Bibliografia | edytuj kod

Na podstawie artykułu: "Liczba zmiennoprzecinkowa" pochodzącego z Wikipedii
OryginałEdytujHistoria i autorzy