Typy danych

Typy danych

Dane typu całkowitego (int, integer)

Typ danych dostępny praktycznie w każdym języku programowania. Współcześnie podstawowa dana typu int zapisywana jest na 32 bitach (4 bajty) w kodzie uzupełnieniowym do dwóch. Z trzydziestu dwu bitów jeden (najbardziej znaczący1) wykorzystywany jest do zapamiętania znaku (zawsze 1 oznacza liczbę ujemną, a 0 — dodatnią), pozostałe służą do zapisu liczby. Dowolną liczbę całkowitą l można przedstawić w postaci rozwinięcia dwójkowego:

$$l = s \sum_{i=0}^{n} e_i 2^i \qquad (e_n \ne 0 \; \mbox{dla}\; l \ne 0)$$

gdzie s jest znakiem liczby (s =  + 1 lub s =  − 1), a ei = 0 lub 1 są cyframi rozwinięcia dwójkowego.

Ogólnie, gdy do zapisu liczby wykorzystujemy d + 1 bitów, to gdy n < d — liczba l może być reprezentowana w wybranej arytmetyce. Może być zapisana jako:

teoria-figure0

W ten sposób mogą być reprezentowane liczby z zakresu [ − 2d, 2d − 1]. We współczesnych maszynach cyfrowych d przyjmuje wartości: 7, 15, 31, 632. Zatem liczby całkowite w zależności od d mogą przyjmować wartości z różnych zakresów (tab. [Zakres]).

Plik nagłówkowy limits.h zawiera definicje kilku stałych, które pozwalają zawsze sprawdzić, jakie graniczne wartości mogą przyjmować zmienne określonego typu. Definiują one stałe nazywajace się: SCHAR_MINSCHAR_MAX (minimalna i maksymalna wartość zmiennej signed char) SHRT_MINSHRT_MAX, INT_MININT_MAX, LONG_MINLONG_MAX czy LLONG_MINLLONG_MAX. Trochę kłopotów może sprawiać typ long int który może mieć różne zakresy w zależności od tego czy komputer jest 32-bitowy czy 64-bitowy. Podczas programowania, korzystając ze stałych takich typów, nalezy pamiętać o odpowiednich przyrostkach: L — long, LL — long long czy U — unsigned, UL — unsigned long, itd.

d typ (C) zakres
7 char [ − 128, 127]
15 short int [ − 32768,  + 32767]
31 int [ − 2147483648,  + 2147483647]
63 long int [ − 9223372036854775808,  + 9223372036854775807]

W zasadzie wszystkie obliczenia na liczbach całkowitych dokonywane są dokładnie. Wyjątki od tej reguły są dwa:

  1. Operacja dzielenia zazwyczaj nie wyprowadza poza typ całkowity. Jest to dzielenie całkowitoliczbowe („z resztą”).
  2. Wynik działania wykracza poza dopuszczalny zakres; podawany jest wówczas modulo 2d.

Dane typu niecałkowitego

Dowolną liczbę rzeczywistą x ≠ 0 można przedstawić w postaci

x = s ⋅ 2cm

gdzie s ( + 1 lub  − 1) to znak liczby, c — liczba całkowita zwana cechą, a m to liczba rzeczywista z przedziału \([\frac{1}{2},1)\) nazywana mantysą. Gdy x ≠ 0 przedstawienie jest jednoznaczne.

W realizacji komputerowej cecha liczby c zapisywana jest na d − t bitach, pozostałe t bitów przeznaczonych jest na reprezentację mantysy m. Zatem zamiast (na ogół nieskończonego) rozwinięcia mantysy:

$$m = \sum_{i=1}^\infty e_{-i}\cdot 2^{-i} \qquad (e_{-1}=1;\; e_i=0\; \mbox{lub}\; 1\; \mbox{dla}\; i>1)$$

korzystamy (gdy mantysa została prawidłowo zaokrąglona do t cyfr):

$$m_t = \sum_{i=1}^t e_{-i}\cdot 2^{-i}$$

Wówczas

$$|m-m_t| \le \frac{1}{2}\cdot 2^{-t}$$

Liczba x binarnie zapisywana jest jako:

teoria-figure1

Jezeli reprezentację zmiennoprzecinkową liczby x oznaczać będziemy \({\mathop{\mathrm{rd}}}(x)\)\({\mathop{\mathrm{rd}}}(x)= s\cdot 2^cm_t\). Dla x ≠ 0

$$\left|\frac{{\mathop{\mathrm{rd}}}(x)-x}{x}\right| \le 2^{-t}$$

co można zapisać:

$${\mathop{\mathrm{rd}}}(x)=x(1+\varepsilon), \qquad \mbox{gdzie}\; |\varepsilon| \le 2^{-t}$$

Liczby rzeczywiste reprezentowane są, na ogół, niedokładnie. Błąd względny ε jest nie większy od 2 − t. We współczesnych komputerach t przyjmuje wartości: 24 dla liczb typu float (32-bitowych) lub 53 (double; 64 bity).

Liczba cyfr mantysy decyduje o dokładności liczb rzeczywistych, a liczba cyfr cechy — o ich zakresie. Cecha c ∈ [cmin, cmax], gdzie cmin =  − cmax − 1 = 2d − t − 1.

Szczegóły zapisu liczb zmiennoprzecinkowych zawiera norma IEEE-754 [1].

Można zaryzykować twierdzenie że zakres liczb i ich precyzja są wystarczająco duże aby prowadzić obliczenia w miarę dokładnie, ale jak przyjrzeć się szczegółom — różnie to bywa. A wynik długotrwałych i skomplikowanych działań może być trudny do przewidzenia.

Programiści języka C mogą korzystać ze stałych zdefiniowanych w pliku nagłówkowym float.h: FLT_MINFLT_MAX, DBL_MINDBL_MAX, a nawet LDBL_MIN/LDBL_MAX dla liczb poczwórnej dokładności (long double) [2]. W przypadku liczb typu float maksymalna wartość to: 3.40282e+38.

Rozważmy prosty przykład:

Niech z będzie liczbą zespoloną z = a + bi, \(\mathrm{i}=\sqrt{-1}\). Z definicji, moduł liczby z równa się:

$$|z|=\sqrt{a\cdot a + b\cdot b}$$

W przypadu gdy wartości ab są bardzo duże (lub bardzo małe) a2 albo b2 mogą nie zmieścić się w dopuszczalnym zakresie. Gdy używamy typu float, a wartość a jest większa od 1.84467341e19 — będziemy mieli kłopot. Ilustruje niższy program.

Modyfikacja polega na tym, że wzór zapisujmy w alternatywnej postaci. Niech |a| > |b|. Wówczas:

$$|z|=\sqrt{a^2+b^2}=a\sqrt{1+\left(\frac{b}{a}\right)^2}.$$

Druga metoda (funkcja modul2() daje poprawne wyniki gdy jej argumenty są bardzo małe jak i bardzo duże.

  • „IEEE standard for floating-point arithmetic,” , 2008. doi:10.1109/IEEESTD.2008.4610935
    [BibTeX] [Abstract] [Download PDF]

    This standard specifies interchange and arithmetic formats and methods for binary and decimal floating-point arithmetic in computer programming environments. This standard specifies exception conditions and their default handling. An implementation of a floating-point system conforming to this standard may be realized entirely in software, entirely in hardware, or in any combination of software and hardware. For operations specified in the normative part of this standard, numerical results and exceptions are uniquely determined by the values of the input data, sequence of operations, and destination formats, all under user control.

    @Standard{ieee754-2008,
    title = {{IEEE} Standard for Floating-Point Arithmetic},
    organization = {IEEE},
    year = {2008},
    url = {http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=4610933},
    abstract = {This standard specifies interchange and arithmetic formats and methods for binary and decimal floating-point arithmetic in computer programming environments. This standard specifies exception conditions and their default handling. An implementation of a floating-point system conforming to this standard may be realized entirely in software, entirely in hardware, or in any combination of software and hardware. For operations specified in the normative part of this standard, numerical results and exceptions are uniquely determined by the values of the input data, sequence of operations, and destination formats, all under user control.},
    doi = {10.1109/IEEESTD.2008.4610935},
    owner = {myszka},
    timestamp = {2015.09.03},
    }

  • Wikibooks, „C programming/c reference/float.h –- wikibooks, the free textbook project,” , 2012.
    [BibTeX] [Download PDF]
    @Electronic{wiki:float.h,
    author = {Wikibooks},
    title = {C Programming/C Reference/float.h --- Wikibooks{,} The Free Textbook Project},
    year = {2012},
    url = {http://en.wikibooks.org/w/index.php?title=C_Programming/C_Reference/float.h&oldid=2371328},
    note = {[Online; accessed 3-September-2015]},
    }


  1. To ten pierwszy z lewej.
  2. Raz jeszcze przypominam, że zapis liczby jest na d + 1 bitach; ten dodatkowy bit, to bit znaku.