Aby ujednolicić wyniki obliczeń numerycznych wykonywanych na różnych platformach sprzętowych, wprowadzono ściśle określony standard zapisu zmiennoprzecinkowego IEEE 754. W następnym rozdziale przedstawiamy wywiad z profesorem Williamem Kahanem - jednym z twórców tego standardu. Jak na warunki szkoły średniej standard IEEE 754 jest dosyć skomplikowany, ponieważ nie został on opracowany do nauki lecz do praktycznych zastosowań inżynierskich i naukowych. Jednakże nie widzę powodów, aby zdolny uczeń liceum nie mógł sobie go przyswoić - wiedza ta zaowocuje na studiach wyższych oraz wpłynie na zrozumienie zalet i ograniczeń obliczeń komputerowych.
Standard IEEE 754 definiuje dwa rodzaje liczb zmiennoprzecinkowych: 32-bitowe (pojedynczej precyzji - ang. single precision) oraz 64-bitowe (podwójnej precyzji - ang. double precision). Kod binarny liczby zmiennoprzecinkowej podzielony jest na trzy pola zawierające komponenty zapisu zmiennoprzecinkowego:
Format zapisu zmiennoprzecinkowego IEEE 754 | |||
---|---|---|---|
32 bity - pojedyncza precyzja | (1 bit) b31 | (8 bitów) b30 ... b23 (BIAS=127) | (23 bity) ,b22 ... b0 (U1) |
64 bity - podwójna precyzja | (1 bit) b63 | (11 bitów) b62 ... b52 (BIAS=1023) | (52 bity) ,b51 ... b0 (U1) |
Opis pół bitowych | bit znaku | bity kodu cechy | bity ułamkowe mantysy |
Bit znaku
Pierwszy bit w zapisie liczby zwany jest bitem znaku. Stan 0 oznacza liczbę dodatnią, stan 1 liczbę ujemną. Aby zatem zmienić znak liczby zmiennoprzecinkowej na przeciwny, wystarczy dokonać negacji tego bitu.
Bity kodu cechy
Liczby zmiennoprzecinkowe IEEE 754 zapisują cechę w kodzie z nadmiarem.
W pojedynczej precyzji cecha posiada 8 bitów, a nadmiar wynosi 127. Zatem w polu cechy można zapisać wartości od -127 (wszystkie bity b30...b23 wyzerowane) do 128 (wszystkie bity b30...b23 ustawione na 1).
W podwójnej precyzji cecha zbudowana jest z 11 bitów, nadmiar wynosi 1023. Najmniejszą wartością będzie -1023 (bity b62...b52 ustawione na 0) , a największą 1024 (bity b62...b52 ustawione na 1). Wzrost ilości bitów cech liczb zmiennoprzecinkowych wpływa a ich zakres.
UWAGA! Cechy zbudowane z samych zer i z samych jedynek pełnią w standardzie IEEE 754 specjalne funkcje nie związane z ich normalnym znaczeniem. Opisujemy to szczegółowo w dalszej części artykułu.
Bity ułamkowe mantysy
W pojedynczej precyzji mantysa posiada 23 bity, a w podwójnej precyzji 52 bity. Wzrost liczby bitów mantys liczb zmiennoprzecinkowych wpływa na ich precyzję, czyli dokładność odwzorowywania liczb rzeczywistych.
Mantysy są zapisywane w stałoprzecinkowym kodzie U1. Ponieważ mantysa jest prawie zawsze znormalizowana (z wyjątkiem wartości zdenormalizowanej, która jest przypadkiem szczególnym liczby zmiennoprzecinkowej IEEE 754), to jej wartość liczbowa zawiera się pomiędzy 1 a 2. Wynika stąd, iż pierwszy bit całkowity mantysy zawsze wynosi 1. Skoro tak, to nie musi on być zapamiętywany - będzie automatycznie odtwarzany w czasie wykonywania obliczeń na liczbie zmiennoprzecinkowej. W polu mantysy zapamiętujemy tylko bity ułamkowe. Dzięki tej prostej sztuczce zyskujemy jeden dodatkowy bit mantysy - zwiększamy jej rozdzielczość do 24 bitów dla formatu pojedynczej precyzji i do 53 bitów dla formatu podwójnej precyzji. Sposób ten nie jest wcale nowy - zastosował go już w 1936 roku niemiecki konstruktor Konrad Zuse w swoich komputerach.
Wartość liczby IEEE 754 obliczamy wg poznanych dotychczas zasad. Z kodu wydzielamy poszczególne pola znaku z, cechy c i mantysy m. Odczytana mantysa zawiera tylko bity ułamkowe. Dodajemy zatem na początku 01 i przecinek. W wyniku otrzymujemy dodatnią liczbę stałoprzecinkową w kodzie U1. Teraz obliczamy wartość cechy i mantysy, a następnie wyliczamy wartość liczby wg wzoru:
L(IEEE 754) = (-1)zm2c
Dla przykładu policzymy wartości kilku liczb w pojedynczej precyzji (dla podwójnej precyzji rachunki są identyczne, lecz bardziej uciążliwe do przeprowadzenia z uwagi na większą liczbę bitów).
Obliczyć wartość dziesiętną liczby zmiennoprzecinkowej: 01000010110010000000000000000000(IEEE 754).
Kod binarny dzielimy na poszczególne pola zawierające kolejno znak, cechę oraz bity ułamkowe mantysy:
0 10000101 10010000000000000000000 z cecha bity ułamkowe mantysy z = 0 - liczba jest dodatnia
c = 10000101(BIAS=127) = 133 - 127 = 6
m = 01,10010000000000000000000(U1) = 19/16Mamy wszystkie niezbędne składniki, wyliczamy wartość liczby:
L(IEEE 754) = (-1)zm2c = (-1)0 x 19/16 x 26 = 25/16 x 26= 25 x 22 = 25 x 4 = 100(10)
01000010110010000000000000000000(IEEE 754) = 100(10).
Obliczyć wartość dziesiętną liczby zmiennoprzecinkowej 11000001110110000000000000000000(IEEE 754).
Postępujemy identycznie jak w poprzednim przykładzie:
1 10000011 10110000000000000000000 z cecha bity ułamkowe mantysy z = 1 - liczba jest ujemna
c = 10000011(BIAS=127) = 131 - 127 = 4
m = 01,10110000000000000000000(U1) = 111/16L(IEEE 754) = (-1)zm2c = (-1)1 x 111/16 x 24 = - 27/16 x 24= -27(10)
11000001110110000000000000000000(IEEE 754) = -27(10).
Obliczyć wartość dziesiętną liczby zmiennoprzecinkowej 10111110000000000000000000000000(IEEE 754).
1 01111100 00000000000000000000000 z cecha bity ułamkowe mantysy z = 1 - liczba jest ujemna
c = 01111100(BIAS=127) = 124 - 127 = -3
m = 01,00000000000000000000000(U1) = 1L(IEEE 754) = (-1)zm2c = (-1)1 x 1 x 2-3 = - 1/8 = -0,125(10)
11000001110110000000000000000000(IEEE 754) = -0,125(10).
Jak widać, liczby zmiennoprzecinkowe wcale nie są takie straszne - pod warunkiem, że pilnie studiowałeś nasz artykuł. W przeciwnym razie na zawsze pozostaną dla ciebie tajemnicą...
Poniżej przedstawiam prosty program w języku Pascal, który pozwala zobaczyć wewnętrzną postać wprowadzonej liczby zmiennoprzecinkowej w standardzie IEEE 754 (program nie uwzględnia wartości specjalnych - ale może ty potrafisz go ulepszyć?). W programie wykorzystujemy fakt, iż komputer IBM PC przechowuje liczby zmiennoprzecinkowe w tym właśnie standardzie, zatem nic nie musimy przeliczać, wszystko robi za nas system.
Efekt uruchomienia programu Demonstracja standardu zmiennoprzecinkowego IEEE 754
----------------------------------------------------
(C)2005 mgr Jerzy Walaszek I LO w Tarnowie
Wpisz liczbe : -13257.25
11000110010011110010010100000000
1 10001100 10011110010010100000000
z cecha mantysa
z = 1
c = 10001100 = 13
m = 01,10011110010010100000000 = 1.6183166504
Klawisz ENTER = KONIEC
program IEEE754;
{$APPTYPE CONSOLE}
type
sp_ieee754 = record
case value: integer of
0 : (b : array[0..3] of byte);
1 : (f : single);
end;
var
l_ieee754 : sp_ieee754;
i,j,v,c,z : integer;
s : string;
begin
writeln('Demonstracja standardu zmiennoprzecinkowego IEEE 754');
writeln('----------------------------------------------------');
writeln('(C)2005 mgr Jerzy Walaszek I LO w Tarnowie');
writeln;
write('Wpisz liczbe : '); readln(l_ieee754.f);
writeln;
//---------------------------------------
// Odczytujemy kolejne bity zapisu liczby
//---------------------------------------
s := '';
for i := 0 to 3 do
begin
v := l_ieee754.b[i];
for j := 1 to 8 do
begin
s := char(48 + (v mod 2)) + s;
v := v div 2;
end;
end;
writeln(s);
writeln;
for i := 1 to 32 do
begin
write(s[i]);
if (i = 1) or (i = 9) then write(' ');
end;
writeln;
writeln('z cecha mantysa');
writeln;
//----------------------------------------------------
// Teraz wyznaczamy wartości poszczególnych składników
// Program nie uwzględnia wartości specjalnych !
//----------------------------------------------------
z := (l_ieee754.b[3] and $80) shr 7;
writeln('z = ',z);
c := ((l_ieee754.b[3] and $7f) shl 1) or
((l_ieee754.b[2] and $80) shr 7) - 127;
writeln('c = ',copy(s,2,8),' = ',c);
v := $800000 or ((l_ieee754.b[2] and $7f) shl 16) or
(l_ieee754.b[1] shl 8) or l_ieee754.b[0];
writeln('m = 01,',copy(s,10,23),' = ',v / $800000:0:10);
writeln;
write('Klawisz ENTER = KONIEC'); readln;
end.
Gdy znamy budowę liczby zmiennoprzecinkowej w standardzie IEEE 754, z obliczeniem zakresu możliwych do zapisania w nim liczb nie będzie żadnego problemu. Po prostu musimy znaleźć największą cechę i największą mantysę i podstawić je do podanego wcześniej wzoru.
Liczby pojedynczej precyzji
Największa cecha posiada kod:
c = 11111110(BIAS=127)
c = 254 - 127
c = 127Kod 11111111(BIAS=127) = 255 - 127 = 128 jest zarezerwowany dla specjalnych sytuacji, zatem nie możemy go wykorzystać na cechę liczby zmiennoprzecinkowej.
Największa mantysa osiada kod:
m = 01,11111111111111111111111(U1)
m = (224 - 1) / 223Obliczamy wartość największej liczby:
max(IEEE 754) = m x 2c
max(IEEE 754) = (224 - 1) / 223 x 2127
max(IEEE 754) = (224 - 1) x 2104
max(IEEE 754) = 3,4028234663852885981170418348452 x 1038a po zaokrągleniu:
max(IEEE 754) = 3,4 x 1038
Ponieważ zmianą znaku możemy uzyskać tę samą wartość po stronie ujemnej, zakres liczb zmiennoprzecinkowych IEEE 754 w pojedynczej precyzji wynosi:
Zakres liczb zmiennoprzecinkowych IEEE 754 w pojedynczej precyzji
| |||
Liczby podwójnej precyzji
Dla liczby IEEE 754 podwójnej precyzji przeprowadzamy identyczne obliczenia:
c = 11111111110(BIAS=1023)
c = 2046 - 1023
c = 1023m = 01,1111111111111111111111111111111111111111111111111111(U1)
m = (253 - 1) / 252max(IEEE 754) = m x 2c
max(IEEE 754) = (253 - 1) / 252 x 21023
max(IEEE 754) = (253 - 1) x 2971
max(IEEE 754) = 1,797693134862315708145274237317 x 10308a po zaokrągleniu:
max(IEEE 754) = 1,8 x 10308
Zakres liczb zmiennoprzecinkowych IEEE 754 w podwójnej precyzji
| |||
Oprócz zakresu, na który wpływa głównie długość formatu bitowego cechy, dla liczb zmiennoprzecinkowych nie mniej ważnym parametrem jest precyzja zapisu, czyli z jaką dokładnością dana liczba może być reprezentowana. Precyzję podaje się najczęściej jako przybliżoną ilość dziesiętnych cyfr znaczących. Na przykład jeśli precyzja zapisu wynosi trzy cyfry dziesiętne, to liczby 856 92,4 1,53 zostaną zapamiętane dokładnie, natomiast liczby o większej ilości cyfr już nie: 85613 zostanie zapamiętane jako 856??, gdzie znaki ? reprezentują dowolne cyfry.
Precyzję zapisu liczby zawsze wyznacza ilość dostępnych bitów mantysy. Jedną cyfrę dziesiętną koduje (statystycznie) log2(10) bitów mantysy. Ułóżmy zatem proste proporcje:
Dla pojedynczej precyzji mantysa ma długość 24 bity:
1 cyfra dziesiętna --- log2(10) bitów
x cyfr dziesiętnych --- 24 bityStąd
x cyfr dziesiętnych = 24 / log2(10) = 24 / 3,32 = 7,2 cyfry
Zaokrąglamy wynik do liczby całkowitej i dla liczb w pojedynczej precyzji otrzymujemy 7 dziesiętnych cyfr znaczących.
Dla podwójnej precyzji mantysa ma długość 53 bity:
1 cyfra dziesiętna --- log2(10) bitów
x cyfr dziesiętnych --- 53 bityStąd
x cyfr dziesiętnych = 53 / log2(10) = 53 / 3,32 = 15,96 cyfry
Zaokrąglamy wynik do liczby całkowitej i dla liczb w podwójnej precyzji otrzymujemy 15-16 cyfr znaczących.
| |||
Wartość zero
Zauważ, iż w normalny sposób nie można zapisać w formacie IEEE 754 wartości 0, ponieważ mantysa ma domyślną część całkowitą równą 1 - w polu mantysy zapamiętywane są jedynie bity ułamkowe. Dlatego zero jest specjalnym przypadkiem liczby zmiennoprzecinkowej, gdzie zarówno pole wykładnika jak i mantysy zawiera same 0. Bit znaku może przyjmować dowolną wartość (stąd możemy dostać dodatnie lub ujemne 0, jednakże przy porównaniu są one traktowane jak równe sobie).
Wartość ZERO pole
znakupole
cechypole
mantysy0/1 0...0 0...0
Wartość zdenormalizowana
Jeśli wszystkie bity cechy mają wartość 0, lecz mantysa zawiera bity o wartościach 1 (w przeciwnym razie liczba zostanie potraktowana jak opisane wcześniej zero), to jest to tzw. zdenormalizowana liczba zmiennoprzecinkowa. W takim przypadku mantysa nie posiada domyślnej części całkowitej 1, lecz jest liczbą ułamkową, której bity zawarte są w polu formatu IEEE 754.
Wartość zdenormalizowana
pole
znakupole
cechypole
mantysy0/1 0...0 bity ułamkowe mantysy
Wartość zdenormalizowaną liczby zmiennoprzecinkowej liczymy według wzoru:
Pojedyncza precyzja
m = 00,(pole mantysy)(U1)
L = (-1)zm2-126
Stąd najmniejszą wartością zmiennoprzecinkową różną od zera jest:
00000000000000000000000000000001(IEEE 754)
m = 00,00000000000000000000001(U1)
m = 2-23min(IEEE 754) = 2-23 x 2-126 = 2-149
min(IEEE 754) = 1,4012984643248170709237295832899 x 10-45
min(IEEE 754) = ±1,4 x 10-45Podwójna precyzja
m = 00,(pole mantysy)(U1)
L = (-1)zm2-1022
Stąd najmniejszą wartością zmiennoprzecinkową różną od zera jest:
000000000000000000000000000000000000000000000000000000000000001(IEEE 754)
m = 00,0000000000000000000000000000000000000000000000000001(U1)
m = 2-52min(IEEE 754) = 2-52 x 2-1022 = 2-1074
min(IEEE 754) = 4,9406564584124654417656879286822 x 10-324
min(IEEE 754) = ±4,9 x 10-324
| |||
Nieskończoność
Standard IEEE 754 pozwala reprezentować dodatnią i ujemną nieskończoność. Pole znaku określa, z którą nieskończonością mamy do czynienia - dodatnią czy ujemną. Cecha posiada wszystkie bity ustawione na 1 (maksymalna wartość cechy), a bity mantysy są wyzerowane.
Nieskończoność pole
znakupole
cechypole
mantysy0/1 1...1 0...0 Wartość typu nieskończoność jest bardzo pożądana w systemie zmiennoprzecinkowym, ponieważ pozwala ona prowadzić obliczenia po wystąpieniu nadmiaru. Wyniki działań z nieskończonościami są dokładnie zdefiniowane w standardzie IEEE 754 - opisujemy je na końcu rozdziału.
Nieliczby
Standard IEEE 754 definiuje dwie specjalne wartości, które nie reprezentują liczb. Stąd nazywane są w literaturze terminem NaN (Not a Number - Nie Liczba). Nieliczby mogą być dwojakiego rodzaju - tzw. ciche - QNaN (ang. Quiet NaN) lub głośne SNaN (ang. Signaling NaN). W obu przypadkach cecha zawiera same 1, a pole mantysy zawiera bity 1. Jeśli najstarszy bit ułamkowy mantysy jest ustawiony na 1, to kod reprezentuje cichą nieliczbę - QNaN.
Cicha Nieliczba
QNaNpole
znakupole
cechypole
mantysy0/1 1...1 1X...X Jeśli najstarszy bit mantysy ustawiony jest na 0, kod reprezentuje głośną nieliczbę:
Głośna Nieliczba
SNaNpole
znakupole
cechypole
mantysy0/1 1...1 0X...X Nieliczby mają wiele zastosowań. Ciche nieliczby przechodzą przez działania arytmetyczne. Najczęściej oznaczają one wartość niezdefiniowaną. Głośne nieliczby powodują powstanie wyjątków w operacjach arytmetycznych. Najczęściej oznaczają one wartość niedozwoloną. Typowym zastosowaniem głośnych nieliczb jest wstępna inicjalizacja zmiennych. Jeśli programista nie wprowadzi do zmiennej wartości, czyli nie zainicjuje jej, to będzie ona zawierała wartość SNaN. Próba użycia takiej zmiennej w jakimkolwiek wyrażeniu arytmetycznym spowoduje wygenerowanie wyjątku i przerwanie obliczeń.
Wyniki operacji z wartościami specjalnymi
Standard IEEE 754 bardzo dokładnie precyzuje wyniki operacji, w których jednym z argumentów (lub obydwoma) jest wartość specjalna. W poniższej tabelce zebraliśmy najważniejsze zasady przeprowadzania takich operacji:
Operacja Wynik n / ±Nieskończoność 0 ±Nieskończoność x ±Nieskończoność ±Nieskończoność ±wartość niezerowa / 0 ±Nieskończoność Nieskończoność + Nieskończoność Nieskończoność ±0 / ±0 NaN Nieskończoność - Nieskończoność NaN ±Nieskończoność / ±Nieskończoność NaN ±Nieskończoność x 0 NaN Zainteresowanych tym tematem odsyłamy do artykułu o komputerach Konrada Zuse.
W poniższej tabelce podsumowujemy wszystkie możliwe wartości reprezentowane przez format IEEE 754. Więcej danych na temat standardu IEEE 754 znajdziesz w witrynie http://standards.ieee.org/.
Interpretacja kodu IEEE 754 Pole
znakuPole
cechyPole
mantysyWartość 0 0...0 0..0 +0 (zero dodatnie) 0 0...0 0...1
:
1...1Dodatnia liczba zdenormalizowana 0 0...1
:
1...00...0
:
1...1Dodatnia liczba zmiennoprzecinkowa 0 1...1 0...0 +Nieskończoność 0 1...1 0...01
:
01...1SNaN (głośna nieliczba) 0 1...1 10...0
:
1...1QNaN (cicha nieliczba) 1 0...0 0...0 -0 (zero ujemne) 1 0...0 0...1
:
1...1Ujemna liczba zdenormalizowana 1 0...01
:
1...100...0
:
1...1Ujemna liczba zmiennoprzecinkowa 1 1...1 0...0 -Nieskończoność 1 1...1 0...01
:
01...1SNaN (głośna nieliczba) 1 1...1 10...0
:
1...1QNaN (cicha nieliczba)
Zadanie 1 (średnio trudne)
Każdy współczesny procesor Pentium zintegrowany jest wewnętrznie z koprocesorem arytmetycznym, który wykonuje sprzętowo operacje na liczbach zmiennoprzecinkowych. Wewnętrznie stosuje on rozszerzony typ danych zmiennoprzecinkowych o następującej specyfikacji formatu:
Format rozszerzony zapisu zmiennoprzecinkowego koprocesora arytmetycznego | |||
---|---|---|---|
80 bitów - rozszerzona precyzja | (1 bit) b79 | (15 bitów) b78 ... b64 (BIAS=16383) | (64 bity) ,b63 ... b0 (U1) |
Opis pół bitowych | bit znaku | bity kodu cechy | bity ułamkowe mantysy |
Na podstawie materiału przedstawionego w tym rozdziale wyznacz kolejno:
- Zakres możliwych do przedstawienia w tym formacie liczb dziesiętnych
- Najmniejszą dziesiętną liczbę zdenormalizowaną
- Precyzję zapisu, czyli liczbę znaczących cyfr dziesiętnych.
Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.
Źródło: mgr Jerzy Wałaszek