Reprezentacja liczb całkowitych w systemie komputerowym

Kurs: Wstęp do programowania
Lekcja 2: Podstawy składni języka programowania
Temat 12: Reprezentacja liczb całkowitych w systemie komputerowym

⇓ spis treści ⇓


Reprezentacja liczb całkowitych w systemach komputerowych to jedno z kluczowych zagadnień informatyki, które wpływa na sposób przechowywania i przetwarzania danych przez komputery. Liczby całkowite są jednym z podstawowych typów danych, a ich reprezentacja i zakres są ściśle powiązane z architekturą komputera oraz zastosowanym systemem kodowania. W tej lekcji omówimy, jak liczby całkowite są reprezentowane w pamięci komputera, jakie są rodzaje reprezentacji oraz jakie ograniczenia i pułapki mogą wystąpić.

Podstawy reprezentacji liczb całkowitych

W komputerach liczby całkowite są reprezentowane w postaci binarnej, czyli jako ciągi zer i jedynek. Każdy bit w pamięci może przyjąć wartość 0 lub 1, co oznacza, że liczby są przechowywane w systemie dwójkowym. W zależności od liczby bitów używanych do reprezentacji liczby, zakres wartości, które można przechowywać, jest ograniczony.

Systemy liczbowe

Liczby całkowite mogą być reprezentowane w różnych systemach liczbowych, takich jak:

  • System dziesiętny: Najbardziej naturalny dla człowieka, używający cyfr od 0 do 9.
  • System binarny: Używany przez komputery, wykorzystujący tylko dwie cyfry: 0 i 1.
  • System ósemkowy: Rzadko używany, oparty na ośmiu cyfrach (0-7).
  • System szesnastkowy: Często używany w programowaniu, oparty na 16 symbolach (0-9 i A-F).
Przykład konwersji liczby dziesiętnej na binarną
liczba_dziesietna = 13
liczba_binarna = bin(liczba_dziesietna)
print("Liczba dziesiętna:", liczba_dziesietna)
print("Liczba binarna:", liczba_binarna)

W powyższym przykładzie liczba dziesiętna 13 jest konwertowana na postać binarną, co daje wynik 1101.

Reprezentacja liczb całkowitych bez znaku

Liczby całkowite bez znaku (unsigned) to liczby nieujemne, które mogą przyjmować tylko wartości od 0 wzwyż. W przypadku użycia n bitów zakres takich liczb wynosi od 0 do 2^n - 1.

Przykład: Reprezentacja liczby 13 na 8-bitach
unsigned int liczba = 13; // 00001101 w zapisie binarnym

W tym przykładzie liczba 13 jest reprezentowana na 8-bitach w postaci binarnej jako 00001101. Najstarszy bit (po lewej stronie) ma najmniejszą wagę, a najmłodszy bit (po prawej stronie) ma największą wagę.

Reprezentacja liczb całkowitych ze znakiem

Liczby całkowite ze znakiem (signed) mogą przyjmować zarówno wartości dodatnie, jak i ujemne. Aby przechowywać znaki, stosuje się różne metody kodowania, takie jak:

  • Kod znak-moduł (sign-magnitude): Najstarszy bit reprezentuje znak (0 – liczba dodatnia, 1 – liczba ujemna), a pozostałe bity reprezentują wartość liczby.
  • Kod uzupełnienia do jedynki: Bity liczby dodatniej są odwracane (zamiana 0 na 1 i 1 na 0), aby uzyskać liczbę ujemną.
  • Kod uzupełnienia do dwóch: Najczęściej stosowana metoda, w której liczba ujemna jest obliczana jako uzupełnienie do dwóch liczby dodatniej.
Kod uzupełnienia do dwóch

W kodzie uzupełnienia do dwóch liczba ujemna jest uzyskiwana przez odwrócenie wszystkich bitów liczby dodatniej i dodanie 1 do wyniku. Na przykład, aby uzyskać -13 na 8-bitach:

liczba_dziesietna = 13
liczba_uzupelnienie_do_dwoch = ~liczba_dziesietna + 1
print("Liczba -13 w kodzie uzupełnienia do dwóch:", bin(liczba_uzupelnienie_do_dwoch & 0xFF))

Wynik to 11110011, co reprezentuje -13 na 8-bitach w kodzie uzupełnienia do dwóch.

Ograniczenia i zakresy liczb całkowitych

Zakres liczb całkowitych zależy od liczby bitów używanych do ich reprezentacji. Na przykład:

  • 8-bitowe liczby bez znaku: Zakres od 0 do 255.
  • 8-bitowe liczby ze znakiem: Zakres od -128 do 127.
  • 16-bitowe liczby bez znaku: Zakres od 0 do 65 535.
  • 16-bitowe liczby ze znakiem: Zakres od -32 768 do 32 767.
  • 32-bitowe liczby bez znaku: Zakres od 0 do 4 294 967 295.
  • 32-bitowe liczby ze znakiem: Zakres od -2 147 483 648 do 2 147 483 647.

Problemy związane z reprezentacją liczb całkowitych

W programowaniu często napotykamy na problemy związane z ograniczeniami reprezentacji liczb całkowitych. Oto kilka typowych problemów:

1. Przepełnienie

Przepełnienie występuje, gdy wynik operacji arytmetycznej przekracza zakres reprezentacji liczby całkowitej. Na przykład, dodanie 1 do największej 8-bitowej liczby bez znaku (255) spowoduje przepełnienie i zwrócenie 0.

unsigned char liczba = 255;
liczba = liczba + 1; // Przepełnienie, wynik: 0
2. Podprzepełnienie

Podprzepełnienie to sytuacja, gdy wynik operacji arytmetycznej jest mniejszy niż minimalna reprezentowalna wartość. Na przykład, odjęcie 1 od najmniejszej liczby 8-bitowej ze znakiem (-128) spowoduje podprzepełnienie i zwrócenie 127.

signed char liczba = -128;
liczba = liczba - 1; // Podprzepełnienie, wynik: 127
3. Truncacja

Truncacja występuje, gdy liczba większa niż zakres zmiennej jest „obcinana” do pasującego zakresu. Może to prowadzić do utraty danych i nieoczekiwanych wyników.

Optymalizacja przechowywania liczb całkowitych

Programiści często muszą optymalizować sposób przechowywania liczb całkowitych, aby zminimalizować zużycie pamięci i zwiększyć wydajność. Wybór odpowiedniego typu danych jest kluczowy, szczególnie w systemach o ograniczonych zasobach.

Typy danych w C++
  • char: 1 bajt, zakres: -128 do 127 (ze znakiem) lub 0 do 255 (bez znaku).
  • short: 2 bajty, zakres: -32 768 do 32 767 (ze znakiem) lub 0 do 65 535 (bez znaku).
  • int: 4 bajty, zakres: -2 147 483 648 do 2 147 483 647 (ze znakiem) lub 0 do 4 294 967 295 (bez znaku).
  • long: 4 lub 8 bajtów, w zależności od systemu.
  • long long: 8 bajtów, zakres: -9 223 372 036 854 775 808 do 9 223 372 036 854 775 807 (ze znakiem).

Praktyczne zastosowania i przykłady

Reprezentacja liczb całkowitych jest kluczowa w wielu dziedzinach, takich jak grafika komputerowa, algorytmy szyfrowania czy systemy baz danych. Na przykład, indeksy w tablicach są reprezentowane jako liczby całkowite bez znaku, aby uniknąć błędów związanych z ujemnymi wartościami.

Przykład: Użycie liczb całkowitych w grafice komputerowej
struct Punkt {
    unsigned int x;
    unsigned int y;
};
Punkt piksel = {800, 600};
std::cout << "Pozycja piksela: (" << piksel.x << ", " << piksel.y << ")" << std::endl;

W tym przykładzie współrzędne piksela są reprezentowane jako liczby całkowite bez znaku, co zapewnia, że nie będą miały wartości ujemnych.

Podsumowanie

Reprezentacja liczb całkowitych w systemie komputerowym jest niezbędnym elementem, który wpływa na sposób przechowywania i przetwarzania danych. Znajomość różnych metod reprezentacji oraz ograniczeń, takich jak przepełnienie czy podprzepełnienie, jest kluczowa dla unikania błędów i pisania wydajnego kodu. Wybierając odpowiedni typ danych, programiści mogą optymalizować wydajność i efektywność aplikacji.

Następny temat ==> Liczby zmiennoprzecinkowe: Zakres i błędy zaokrągleń



Spis Treści - Wstęp do programowania

Lekcja 3: Rozwiązywanie problemów i poprawność programów Lekcja 4: Praca z różnymi typami danych Lekcja 5: Obsługa plików i pamięci Lekcja 6: Zaawansowane techniki programistyczne Lekcja 7: Wskaźniki i pamięć dynamiczna Lekcja 8: Struktura kodu i abstrakcja Lekcja 9: Rekurencja i jej zastosowania Lekcja 10: Analiza wydajności algorytmów Lekcja 11: Technika "dziel i zwyciężaj" Lekcja 12: Struktury danych o dynamicznej budowie Lekcja 13: Struktury hierarchiczne: Drzewa Lekcja 14: Struktury danych z bibliotek Lekcja 15: Algorytmy z nawrotami Lekcja 16: Programowanie dynamiczne Lekcja 17: Programowanie zachłanne Lekcja 18: Praca z grafami

Jeśli chciałbyś być poinformowany o następnych kursach to zapisz się do naszego newslettera: