System dziesiątkowy
Kodowanie,  Poradnik

System dziesiątkowy

Liczby zapisane w codziennych obliczeniach wyglądają pozornie banalnie. Człowiek wpisuje 2026, 3,14 albo 150000 i rzadko zastanawia się, dlaczego akurat taki zapis działa. Dopiero podczas programowania parserów, implementacji arytmetyki w procesorach albo analizy reprezentacji danych wychodzi na jaw, że sposób zapisu liczby ma ogromne znaczenie dla szybkości obliczeń, zużycia pamięci i odporności na błędy. W praktyce informatycznej problemy zaczynają się bardzo szybko: przepełnienia typów, błędy zaokrągleń, niepoprawne konwersje między systemami pozycyjnymi albo błędne interpretowanie danych binarnych. W takich sytuacjach fundamentem staje się System dziesiątkowy i jego matematyczna konstrukcja.

System dziesiątkowy jako pozycyjny sposób zapisu liczb oparty na podstawie dziesięć

System dziesiątkowy jest pozycyjnym systemem liczbowym o podstawie 10. Oznacza to, że każda pozycja cyfry w liczbie reprezentuje kolejną potęgę liczby 10. Człowiek używa dziesięciu cyfr:

CyfraWartość
0zero
1jeden
2dwa
3trzy
4cztery
5pięć
6sześć
7siedem
8osiem
9dziewięć

Kluczowe jest tutaj pojęcie pozycyjności. W liczbie 582 cyfra 5 nie oznacza po prostu „pięć”. Ona oznacza pięć setek.

PozycjaCyfraWartość
10210^21025500
10110^1101880
10010^010022

Całą liczbę można więc rozpisać:

582=5102+8101+2100582 = 5 \cdot 10^2 + 8 \cdot 10^1 + 2 \cdot 10^0582=5⋅102+8⋅101+2⋅100

To samo działa dla liczb ułamkowych.

PozycjaCyfraWartość
10010^010033
10110^{-1}10−110,1
10210^{-2}10−240,04

Dla liczby 3,14:

3,14=3100+1101+41023{,}14 = 3 \cdot 10^0 + 1 \cdot 10^{-1} + 4 \cdot 10^{-2}3,14=3⋅100+1⋅10−1+4⋅10−2

To właśnie potęgi podstawy są najważniejszym elementem każdego pozycyjnego systemu liczbowego. W systemie binarnym podstawą jest 2, w ósemkowym 8, a w szesnastkowym 16.

Warto zauważyć praktyczny aspekt pozycyjności. Gdyby zapis nie był pozycyjny, trzeba byłoby stosować ogromną liczbę symboli. System rzymski jest dobrym przykładem problemu. Liczba 3888 wygląda tam tak:

SystemZapis
Dziesiętny3888
RzymskiMMMDCCCLXXXVIII

W systemie rzymskim praktycznie nie da się efektywnie implementować algorytmów arytmetycznych. Dodawanie czy mnożenie wymaga manipulacji symbolami zamiast prostych operacji pozycyjnych.

Dlaczego człowiek używa podstawy dziesięć i jakie ma to konsekwencje w informatyce

Najczęściej przyjmuje się, że wybór podstawy 10 wynika z anatomii człowieka. Dziesięć palców ułatwiało liczenie już w starożytności. Z perspektywy informatyki nie jest to jednak rozwiązanie idealne.

Procesory pracują binarnie. Dla elektroniki dużo prostsze jest rozróżnianie dwóch stanów:

StanInterpretacja
brak napięcia0
napięcie obecne1

Dlatego komputer wewnętrznie nie przechowuje liczb dziesiętnych w postaci znaków „0-9”. Zamiast tego używa reprezentacji binarnej.

Liczba dziesiętna 13 wygląda tak:

SystemZapis
Dziesiętny13
Binarny1101

Rozwinięcie pozycyjne:

11012=123+122+021+1201101_2 = 1 \cdot 2^3 + 1 \cdot 2^2 + 0 \cdot 2^1 + 1 \cdot 2^011012​=1⋅23+1⋅22+0⋅21+1⋅20

To prowadzi do bardzo ważnego problemu praktycznego. Nie każdą liczbę dziesiętną można dokładnie zapisać w systemie binarnym.

Przykład:

Liczba dziesiętnaPrzybliżenie binarne
0,1nieskończone rozwinięcie

W Pythonie:

PythonWynik
0.1 + 0.20.30000000000000004
a = 0.1
b = 0.2

print(a + b)

To nie jest błąd języka. To efekt reprezentacji liczb zmiennoprzecinkowych.

W C:

CWynik
0.1 + 0.2niedokładne przybliżenie
#include <stdio.h>

int main() {
double a = 0.1;
double b = 0.2;

printf("%.17f\n", a + b);

return 0;
}

W praktyce finansowej takie błędy są bardzo niebezpieczne. System bankowy nie może zgubić nawet jednego grosza przez niedokładność reprezentacji.

Dlatego wiele systemów księgowych stosuje:

  • liczby całkowite reprezentujące grosze,
  • arytmetykę stałoprzecinkową,
  • specjalne typy decimal.

System dziesiątkowy w algorytmach konwersji między reprezentacjami liczbowymi

Konwersja do systemu binarnego jest jednym z podstawowych ćwiczeń z informatyki teoretycznej.

Dla liczby całkowitej stosuje się kolejne dzielenia przez 2.

Przykład dla liczby 25:

DzielenieReszta
25 / 2 = 121
12 / 2 = 60
6 / 2 = 30
3 / 2 = 11
1 / 2 = 01

Czytając reszty od końca:

DziesiętnieBinarnie
2511001

Implementacja w C:

Kod COpis
dzielenie przez 2generowanie kolejnych bitów
#include <stdio.h>

void decimalToBinary(int n) {
int bits[32];
int i = 0;

while(n > 0) {
bits[i] = n % 2;
n = n / 2;
i++;
}

for(i = i - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
}

int main() {
decimalToBinary(25);
return 0;
}

W Pythonie można zrobić to znacznie prościej:

Kod PythonOpis
funkcja bin()wbudowana konwersja
n = 25
print(bin(n))

Konwersja odwrotna polega na sumowaniu potęg liczby 2.

Dla liczby binarnej 101101:

1011012=125+024+123+122+021+120101101_2 = 1 \cdot 2^5 + 0 \cdot 2^4 + 1 \cdot 2^3 + 1 \cdot 2^2 + 0 \cdot 2^1 + 1 \cdot 2^01011012​=1⋅25+0⋅24+1⋅23+1⋅22+0⋅21+1⋅20

Po obliczeniu:

SkładnikWartość
1321 \cdot 321⋅3232
0160 \cdot 160⋅160
181 \cdot 81⋅88
141 \cdot 41⋅44
020 \cdot 20⋅20
111 \cdot 11⋅11

Suma:

WynikWartość
dziesiętnie45

Takie algorytmy są fundamentem działania kompilatorów, parserów liczb i interpreterów języków programowania.

Reprezentacja liczb całkowitych i ograniczenia pamięci w komputerach

Komputer nie przechowuje liczb „bez końca”. Każda liczba zajmuje określoną liczbę bitów.

Najczęstsze typy:

TypRozmiarZakres
uint88 bitów0–255
int1616 bitów-32768–32767
int3232 bityokoło ±2 miliardy
int6464 bityokoło ±9 trylionów

Dla typu bez znaku 8-bitowego:

28=2562^8 = 25628=256

Ponieważ pierwszy stan to 0, zakres kończy się na 255.

Problem przepełnienia jest bardzo praktyczny.

Kod w C:

KodProblem
przepełnienie typuutrata poprawności
#include <stdio.h>

int main() {
unsigned char x = 255;

x = x + 1;

printf("%d\n", x);

return 0;
}

Wynik:

OperacjaWynik
255 + 10

To zjawisko nazywa się overflow.

W systemach embedded taki błąd może:

  • zatrzymać sterownik,
  • uszkodzić pomiar czujnika,
  • wywołać błędne sterowanie silnikiem,
  • zniszczyć dane telemetryczne.

W praktyce przemysłowej overflow jest jednym z najczęstszych źródeł trudnych do wykrycia błędów.

Operacje arytmetyczne wykonywane pozycyjnie i ich implementacja w programach

Dodawanie w systemie dziesiętnym jest algorytmem pozycyjnym. Człowiek wykonuje je kolumnowo.

Przykład:

OperacjaWynik
458 + 376834

Rozpisanie:

KolumnaDziałanie
jedności8 + 6 = 14
dziesiątki5 + 7 + 1 = 13
setki4 + 3 + 1 = 8

Mechanizm przeniesienia jest identyczny jak w procesorze.

Dodawanie binarne:

ABWynik
000
011
101
1110

Ostatni przypadek generuje przeniesienie.

Procesory implementują to sprzętowo przez:

  • półsumatory,
  • pełne sumatory,
  • układy logiczne XOR, AND, OR.

Prosty przykład dodawania binarnego:

10112+01102=1000121011_2 + 0110_2 = 10001_210112​+01102​=100012​

W językach programowania większość tych operacji jest ukryta, ale czasami trzeba je rozumieć bardzo dokładnie, zwłaszcza podczas:

  • optymalizacji,
  • programowania sterowników,
  • pracy z kryptografią,
  • implementacji kompresji danych.

Liczby zmiennoprzecinkowe i problem niedokładności reprezentacji wartości dziesiętnych

IEEE 754 jest standardem reprezentacji liczb zmiennoprzecinkowych.

Liczba float składa się z:

ElementZnaczenie
bit znakudodatnia/ujemna
wykładnikskala
mantysaczęść znacząca

Dla float32:

PoleLiczba bitów
znak1
wykładnik8
mantysa23

To daje ogromny zakres liczb, ale kosztem dokładności.

Przykład problemu:

x = 0.1

for i in range(10):
x += 0.1

print(x)

Oczekiwane:

OczekiwaneFaktyczne
1.11.099999999…

W praktyce inżynierskiej porównywanie floatów operatorem == jest częstym błędem.

Zamiast:

a == b

stosuje się:

abs(a - b) < 0.000001

W symulacjach fizycznych błędy zmiennoprzecinkowe potrafią narastać przez tysiące iteracji. W grafice 3D prowadzi to do drgań obiektów, błędów kolizji albo niestabilności kamery.

Zastosowania systemów liczbowych w sieciach komputerowych, kryptografii i programowaniu niskopoziomowym

Adres IPv4 wygląda dziesiętnie:

AdresPostać
192.168.1.1zapis dziesiętny

W rzeczywistości to cztery bajty:

SegmentBinarnie
19211000000
16810101000
100000001
100000001

Maski sieciowe opierają się na bitach.

Dla maski /24:

11111111.11111111.11111111.0000000011111111.11111111.11111111.0000000011111111.11111111.11111111.00000000

W kryptografii liczby są jeszcze większe. Algorytm RSA używa liczb mających setki lub tysiące bitów.

Przykładowo:

  • klucz RSA 2048 ma długość 2048 bitów,
  • to około 617 cyfr dziesiętnych,
  • zwykły typ int64 jest za mały.

Dlatego biblioteki kryptograficzne implementują arytmetykę wielkich liczb.

W C++:

BibliotekaZastosowanie
GMPliczby arbitralnej długości
OpenSSL BIGNUMkryptografia

Bez takich mechanizmów niemożliwe byłoby:

  • szyfrowanie HTTPS,
  • podpis cyfrowy,
  • blockchain,
  • certyfikaty TLS.

System dziesiątkowy w kontekście edukacji matematycznej oraz rozwoju myślenia algorytmicznego

Dla wielu osób nauka systemów liczbowych kończy się na podstawówce. Potem pojawia się przekonanie, że to tylko „cyferki”. W praktyce brak zrozumienia pozycyjności utrudnia później:

  • debugowanie,
  • analizę pamięci,
  • pracę z protokołami sieciowymi,
  • rozumienie reprezentacji danych.

Uczeń, który rozumie:

  • potęgi podstawy,
  • reprezentację binarną,
  • przeniesienia,
  • zakresy typów,

znacznie szybciej rozumie później:

  • wskaźniki,
  • kodowanie UTF,
  • kompresję,
  • hashowanie,
  • kryptografię.

Bardzo często problemy początkujących programistów nie wynikają z trudności języka, tylko z braku fundamentów matematycznych.

Przykład błędnego myślenia:

ProblemRzeczywista przyczyna
„komputer źle liczy”niedokładność float
„wartość się zepsuła”overflow
„sieć nie działa”błędna maska binarna

Te problemy wracają przez całe życie zawodowe programisty.

Typowe błędy podczas pracy z liczbami i sytuacje prowadzące do trudnych awarii systemów

Najczęstsze błędy:

ProblemSkutek
overflowbłędne dane
underflowutrata dokładności
porównywanie floatówbłędne warunki
błędna konwersja typówutrata informacji
używanie złego zakresuawarie

Przykład w C++:

#include <iostream>

int main() {
int a = 2000000000;
int b = 2000000000;

int c = a + b;

std::cout << c << std::endl;

return 0;
}

Wynik może być ujemny przez przepełnienie.

W systemach czasu rzeczywistego takie sytuacje są szczególnie niebezpieczne. Sterownik może otrzymać wartość spoza zakresu i wykonać fizycznie niebezpieczne działanie.

Dlatego w praktyce przemysłowej stosuje się:

  • walidację zakresów,
  • typy o większej precyzji,
  • testy graniczne,
  • analizę statyczną kodu,
  • arytmetykę bezpieczną.

FAQ

Dlaczego komputer używa systemu binarnego zamiast dziesiętnego?

Elektronika cyfrowa łatwo rozróżnia dwa stany: obecność napięcia i jego brak. Implementacja dziesięciu stabilnych poziomów napięcia byłaby znacznie trudniejsza i bardziej podatna na zakłócenia.

Czy liczba 0,1 może być dokładnie zapisana binarnie?

Nie. W systemie binarnym 0,1 ma nieskończone rozwinięcie okresowe, podobnie jak 1/3 w systemie dziesiętnym.

Dlaczego przepełnienie typu jest groźne?

Bo program zwykle nie zgłasza błędu. Wynik po prostu „zawija się” do innej wartości, co może prowadzić do błędnych decyzji systemu.

Po co programiście znajomość systemów liczbowych?

Bez tego trudno poprawnie rozumieć pamięć, reprezentację danych, protokoły sieciowe, operacje bitowe i ograniczenia sprzętu.

Dlaczego liczby float nie nadają się do finansów?

Ponieważ reprezentują wartości przybliżone. W finansach nawet minimalny błąd zaokrąglenia może powodować realne straty.

Czym różni się liczba całkowita od zmiennoprzecinkowej?

Liczba całkowita przechowuje dokładną wartość bez części ułamkowej. Float przechowuje przybliżenie liczby rzeczywistej.

Dlaczego adres IP zapisuje się dziesiętnie, skoro komputer używa bitów?

Dla człowieka zapis binarny byłby niewygodny. Dziesiętny zapis IPv4 jest tylko reprezentacją czytelną dla użytkownika.

Czy istnieją komputery dziesiętne?

Tak, ale są rzadkie. Niektóre kalkulatory i specjalistyczne systemy finansowe używają arytmetyki dziesiętnej.

Źródło Foto: Freepik

Dodaj komentarz