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=si=0nei2i(en0dlal0) 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:

Reprezentacja binarna liczby całkowitej

W ten sposób mogą być reprezentowane liczby z zakresu [2d,2d1]. 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 ().

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

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_MIN i INT_MAX, LONG_MINLONG_MAX czy LLONG_MIN i LLONG_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.

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

  1. Operacja dzielenia nigdy 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ą x0 można przedstawić w postaci x=s2cm gdzie s (+1 lub 1) to znak liczby, c — liczba całkowita zwana cechą, a m to liczba rzeczywista z przedziału [12,1) nazywana mantysą. Gdy x0 przedstawienie jest jednoznaczne3.

![]“Problemy z liczbami zmiennoprzecinkowymi”(./floating-point.png “Problemy z liczbami zmiennoprzecinkowymi, za Examples of floating point problems)

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

m=i=1ei2i(e1=1;ei=0lub1dlai>1)

korzystamy (gdy mantysa została prawidłowo zaokrąglona do t cyfr): mt=i=1tei2i Wówczas |mmt|122t

Liczba x binarnie zapisywana jest jako:

Reprezentacja binarna liczby zmiennoprzecinkowej

Jezeli reprezentację zmiennoprzecinkową liczby x oznaczać będziemy rd(x) i rd(x)=s2cmt. Dla x0

|rd(x)xx|2t

co można zapisać: rd(x)=x(1+ε),gdzie|ε|2t

Liczby rzeczywiste reprezentowane są, na ogół, niedokładnie. Błąd względny ε jest nie większy od 2t. 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=cmax1=2dt1.

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

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_MIN i FLT_MAX, DBL_MIN i DBL_MAX, a nawet LDBL_MIN/LDBL_MAX dla liczb poczwórnej dokładności(long double) . 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, i=1. Z definicji, moduł liczby z równa się:

|z|=aa+bb

W przypadu gdy wartości a i b 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.

#include <stdio.h>
#include <math.h>
float
modul1 (float a, float b)
{
  return sqrtf (a * a + b * b);
}

float
modul3 (float a, float b)
{
  return fabs (a) * sqrtf (1 + powf (fabs (b) / fabs (a), 2));
}

float
modul2 (float a, float b)
{
  if (fabs (a) > fabs (b))
    return modul3 (a, b);
  else
    return modul3 (b, a);
}

int
main (int argc, char *argv[])
{
  float m;
  m = modul1 (2e-25f, 2e-25f);
  printf ("Bardzo male\n");
  printf ("modul1=%g\n", m);
  m = modul2 (2e-25f, 2e-25f);
  printf ("modul2=%g\n", m);
  printf ("Bardzo duze\n");
  m = modul1 (2e25f, 2e25f);
  printf ("modul1=%g\n", m);
  m = modul2 (2e25f, 2e25f);
  printf ("modul2=%g\n", m);
  return 0;
}

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

|z|=a2+b2=a1+(ba)2.

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

Domyślny typ

Matlab

Domyślnym typem dla obliczeń numerycznych w Matlabie jest typ double.

Nie wyklucza to użycia zmiennych innego typu, ale trzeba je osobno deklarować

Więcej na ten temat można znaleźć w odpowiednim tutorialu.

Mathematica

W przypadku Mathematici, która zazwyczaj wszystkie obliczenia wykonuje symbolicznie sprawa jest znacznie bardziej skomplikowana.

Funkcja N[] pozwala podać żądaną precyzję obliczeń

In[1] := N[1/7]
Out[1] := 0.142857

Jeżeli precyzji nie podamy — obliczenia będą wykonywane z tak zwaną precyzją maszynową. Wówczas obliczenia prowadzone są w arytmetyce 64-bitowej.

Jeżeli precyzję zadamy — wygląda to tak:

In[1]:= N[1/7,50]                                                       
Out[1]= 0.14285714285714285714285714285714285714285714285714

  1. To ten pierwszy z lewej. ↩︎

  2. Raz jeszcze przypominam, że zapis liczby jest na d+1 bitach; ten dodatkowy bit, to bit znaku↩︎

  3. Określenia mantysa i cecha są niepoprawne, ale ciągle jeszcze tradycyjnie używane przy opisie liczb zmiennoprzecinkowych. Po angielsku zamiast mantysa używa się określenia significant; cecha to exponent. Polska Wikipedia pozostaje przy mantysa, choć dodaje też liczba ułamkowa; obok cecha dodaje wykładnik… ↩︎

Poprzedni
Następny