Przewodnik dewelopera po konwersji systemów liczbowych: binarny, hex, ósemkowy i dziesiętny
Pewnego popołudnia wpatrujesz się w 0x7FFF5FBFF8C0 w debuggerze, potem przełączasz się do pliku CSS, aby poprawić #FF5733, a chwilę później uruchamiasz chmod 755 w terminalu. Trzy różne reprezentacje liczb, ta sama arytmetyka pod spodem. Jeśli kiedykolwiek zatrzymałeś się, by w głowie przeliczyć między hex a binarnym, albo zastanawiałeś się, dlaczego uprawnienia Unix korzystają akurat z systemu ósemkowego, ten przewodnik pomoże te skojarzenia złożyć w całość.
Omówimy cztery systemy liczbowe pojawiające się w codziennym programowaniu, trzy metody konwersji warte zapamiętania oraz prawdziwy kod w JavaScripcie, Pythonie, Go i C. Jeśli wolisz pominąć teorię i po prostu przeliczyć liczbę, otwórz nasz Konwerter systemów liczbowych — obsługuje dowolny system od 2 do 36 z dowolną precyzją.
Cztery systemy liczbowe, z których korzysta każdy deweloper
Każda podstawa istnieje w programowaniu z praktycznego powodu, a nie z przypadku historycznego.
System dwójkowy (podstawa 2) — język maszyny
Dwie cyfry: 0 i 1. Tranzystor jest albo włączony, albo wyłączony — to fizyczne ograniczenie daje nam system dwójkowy. Spotkasz go bezpośrednio podczas pracy z maskami bitowymi, flagami funkcji, operacjami bitowymi i obliczeniami podsieci IP.
System dwójkowy szybko staje się nieporęczny. Liczba dziesiętna 255 to w zapisie binarnym 11111111 — osiem cyfr na wartość, która mieści się w trzech cyfrach dziesiętnych. Właśnie dlatego programiści rzadko piszą surowy zapis binarny — robią to tylko wtedy, gdy ważne są pojedyncze pozycje bitów.
System ósemkowy (podstawa 8) — uniksowy skrót
Osiem cyfr: od 0 do 7. Każda cyfra ósemkowa odpowiada dokładnie trzem bitom binarnym, co tłumaczy, dlaczego uprawnienia plików w Uniksie korzystają z systemu ósemkowego — chmod 755 upakowuje trzy grupy po trzy bity uprawnień w trzy czytelne cyfry.
System ósemkowy odgrywał większą rolę w erze PDP-11, kiedy słowa maszynowe dzieliły się równo na 3-bitowe grupy. Dziś sprowadza się głównie do uprawnień Uniksa oraz okazjonalnego literału w C poprzedzonego znakiem 0 (co wywołało już niejedne błędy o jeden, gdy ktoś napisał 0177, oczekując dziesiętnej wartości 177).
System dziesiętny (podstawa 10) — domyślny dla człowieka
Dziesięć cyfr: od 0 do 9. To system, do którego domyślnie wraca twój mózg — numery portów, indeksy tablic, kody statusu HTTP, wymiary pikseli. Komputery nie myślą dziesiętnie, ale ludzie tak — dlatego każda liczba prezentowana użytkownikowi pojawia się w podstawie 10.
System szesnastkowy (podstawa 16) — szwajcarski scyzoryk dewelopera
Szesnaście symboli: 0-9 oraz A-F. Każda cyfra szesnastkowa reprezentuje dokładnie cztery bity binarne (nibble), co czyni hex idealną zwartą reprezentacją danych binarnych. Dwie cyfry szesnastkowe = jeden bajt. Zawsze.
Hex zobaczysz w adresach pamięci (0x7FFF5FBFF8C0), kolorach CSS (#FF5733), adresach MAC (00:1A:2B:3C:4D:5E), formacie UUID i skrótach hash. To lingua franca programowania na poziomie bajtów.
Spróbuj przeliczać między wszystkimi czterema systemami w naszym Konwerterze systemów liczbowych — wpisz wartość w dowolnym systemie i obserwuj, jak pozostałe aktualizują się natychmiast.
Jak działa konwersja: trzy podstawowe metody
Nie potrzebujesz narzędzia, żeby przeliczać między systemami, choć z pewnością przyspieszy ono pracę. Trzy metody pokrywają każdy przypadek.
Metoda 1 — rozwinięcie pozycyjne (dowolny system → dziesiętny)
Każdy pozycyjny system liczbowy działa tak samo: każda cyfra jest mnożona przez podstawę podniesioną do potęgi równej numerowi pozycji, liczonej od prawej, począwszy od zera.
Liczba dwójkowa 1011:
1×2³ + 0×2² + 1×2¹ + 1×2⁰
= 8 + 0 + 2 + 1
= 11
Liczba szesnastkowa FF:
15×16¹ + 15×16⁰
= 240 + 15
= 255
W kodzie większość języków obsługuje to przez funkcję parsującą:
parseInt('1011', 2) // 11
parseInt('FF', 16) // 255
parseInt('755', 8) // 493
Metoda 2 — wielokrotne dzielenie (dziesiętny → dowolny system)
Aby pójść w drugą stronę, należy wielokrotnie dzielić liczbę dziesiętną przez podstawę docelową i zapisywać reszty. Reszty czytamy od dołu do góry.
Liczba dziesiętna 255 → szesnastkowa:
255 ÷ 16 = 15 reszta 15 (F)
15 ÷ 16 = 0 reszta 15 (F)
→ Czytaj od dołu: FF
Liczba dziesiętna 42 → dwójkowa:
42 ÷ 2 = 21 reszta 0
21 ÷ 2 = 10 reszta 1
10 ÷ 2 = 5 reszta 0
5 ÷ 2 = 2 reszta 1
2 ÷ 2 = 1 reszta 0
1 ÷ 2 = 0 reszta 1
→ Czytaj od dołu: 101010
bin(42) # '0b101010'
hex(255) # '0xff'
oct(493) # '0o755'
Metoda 3 — grupowanie bitów (binarny ↔ hex/ósemkowy bezpośrednio)
To metoda, której doświadczeni deweloperzy używają najczęściej. Ponieważ 16 = 2⁴, a 8 = 2³, można konwertować między systemem binarnym a szesnastkowym (lub ósemkowym), grupując bity bezpośrednio — bez żadnych obliczeń.
Binarny → szesnastkowy: grupuj po cztery bity (nibble) od prawej. Dopełnij skrajnie lewą grupę zerami, jeśli to konieczne.
Binarnie: 1010 1111
Hex: A F
→ AF
Binarny → ósemkowy: grupuj po trzy bity od prawej.
Binarnie: 111 101 101
Ósemkowo: 7 5 5
→ 755
Tabelę odwzorowań nibble warto zachować w pamięci:
| Binarnie | Hex | Binarnie | Hex |
|---|---|---|---|
0000 | 0 | 1000 | 8 |
0001 | 1 | 1001 | 9 |
0010 | 2 | 1010 | A |
0011 | 3 | 1011 | B |
0100 | 4 | 1100 | C |
0101 | 5 | 1101 | D |
0110 | 6 | 1110 | E |
0111 | 7 | 1111 | F |
Gdy ta tabela siądzie w głowie, konwersja binarny-hex staje się operacją „spójrz i przeczytaj”.
Konwersja systemów liczbowych w każdym języku
Oto jak obsłużyć konwersję systemów liczbowych w czterech językach, w których pojawia się ona najczęściej.
JavaScript / TypeScript
// Parsowanie: ciąg znaków w dowolnym systemie → liczba
parseInt('FF', 16) // 255
parseInt('101010', 2) // 42
parseInt('755', 8) // 493
// Formatowanie: liczba → ciąg znaków w dowolnym systemie
(255).toString(16) // 'ff'
(42).toString(2) // '101010'
(493).toString(8) // '755'
// Literały
const bin = 0b11111111; // 255
const oct = 0o377; // 255
const hex = 0xff; // 255
// BigInt dla wartości powyżej 2⁵³
const big = BigInt('0xFFFFFFFFFFFFFFFF');
big.toString(2) // 64 jedynki
big.toString(10) // '18446744073709551615'
Python
# Dziesiętny → inne systemy (zwraca ciągi z prefiksem)
bin(255) # '0b11111111'
oct(493) # '0o755'
hex(255) # '0xff'
# Inne systemy → dziesiętny
int('11111111', 2) # 255
int('FF', 16) # 255
int('755', 8) # 493
# Sformatowane wyjście z dopełnieniem
f'{255:08b}' # '11111111' (8-cyfrowy zapis binarny, dopełniony zerami)
f'{255:02x}' # 'ff' (2-cyfrowy hex, małe litery)
f'{255:02X}' # 'FF' (2-cyfrowy hex, wielkie litery)
# Liczby całkowite w Pythonie mają domyślnie dowolną precyzję
big = int('F' * 64, 16) # 256-bitowa liczba, bez przepełnienia
Go
package main
import (
"fmt"
"strconv"
)
func main() {
// Formatowanie: int → string w dowolnym systemie
fmt.Println(strconv.FormatInt(255, 16)) // "ff"
fmt.Println(strconv.FormatInt(255, 2)) // "11111111"
fmt.Println(strconv.FormatInt(493, 8)) // "755"
// Parsowanie: string w dowolnym systemie → int
n, _ := strconv.ParseInt("FF", 16, 64) // 255
fmt.Println(n)
// Specyfikatory Printf
fmt.Printf("%b %o %x %d\n", 255, 255, 255, 255)
// 11111111 377 ff 255
}
C
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
// Wyjście dziesiętne, ósemkowe, szesnastkowe
printf("%d %o %x\n", 255, 255, 255);
// 255 377 ff
// Parsowanie z dowolnego systemu
long val = strtol("FF", NULL, 16); // 255
long bin = strtol("101010", NULL, 2); // 42
// Brak wbudowanego printf dla zapisu binarnego — ekstrakcja ręczna:
uint8_t byte = 0xAF;
for (int i = 7; i >= 0; i--)
putchar(((byte >> i) & 1) ? '1' : '0');
// 10101111
return 0;
}
Realne scenariusze konwersji systemów liczbowych
Pięć sytuacji, w których konwersja systemów przestaje być akademicka i staje się częścią pracy.
1. Debugowanie adresów pamięci
Debugger pokazuje wskaźnik pod adresem 0x7FFF5FBFF8C0. Zamiana ostatnich dwóch bajtów na zapis binarny — 1000 1100 0000 — ujawnia, że adres jest wyrównany do granicy 64 bajtów (sześć końcowych zer). Wyrównanie ma znaczenie dla wydajności pamięci podręcznej, operacji SIMD i wejścia/wyjścia mapowanego w pamięci. Reprezentacja szesnastkowa pozwala dostrzec te wzorce na pierwszy rzut oka.
O arytmetyce wskaźników też łatwiej rozumować w hex. Offset 0x100 od adresu bazowego to dokładnie 256 bajtów — jedna strona w wielu systemach wbudowanych. Dziesiętnie nie jest to już tak oczywiste.
2. Kolory hex w CSS ↔ RGB
Kolor #FF5733 to trzy bajty zapakowane jako pary szesnastkowe:
| Para | Hex | Dziesiętnie | Kanał |
|---|---|---|---|
FF | FF | 255 | Czerwony (max) |
57 | 57 | 87 | Zielony |
33 | 33 | 51 | Niebieski |
Skrócony zapis taki jak #F00 rozwija się do #FF0000 — czysta czerwień. Wariant 8-cyfrowy #FF573380 dodaje kanał alfa, w którym 80 (dziesiętnie 128) odpowiada w przybliżeniu 50% nieprzezroczystości.
Znajomość odwzorowania hex-dziesiętny oznacza mniej wycieczek do próbnika kolorów, gdy chcesz podbić lub obniżyć kanał o konkretną wartość.
3. Uprawnienia plików w Uniksie (system ósemkowy)
chmod 755 rozkłada się następująco:
7 → 111 → rwx (właściciel: read + write + execute)
5 → 101 → r-x (grupa: read + execute)
5 → 101 → r-x (pozostali: read + execute)
Każda cyfra ósemkowa koduje dokładnie jedną grupę uprawnień, ponieważ trzy bity uprawnień (read=4, write=2, execute=1) odwzorowują się na jedną cyfrę ósemkową (0-7). Typowe wzorce:
| Ósemkowo | Binarnie | Uprawnienia | Typowe zastosowanie |
|---|---|---|---|
755 | 111 101 101 | rwxr-xr-x | Pliki wykonywalne, katalogi |
644 | 110 100 100 | rw-r--r-- | Zwykłe pliki |
700 | 111 000 000 | rwx------ | Prywatne skrypty |
600 | 110 000 000 | rw------- | Klucze SSH, sekrety |
4. Obliczenia podsieci sieciowych
Maska podsieci /24 oznacza 24 wiodące jedynki w zapisie binarnym:
11111111.11111111.11111111.00000000
→ 255.255.255.0
Aby znaleźć adres sieci, zastosuj operację AND między IP a maską w zapisie binarnym:
192.168.1.37 → 11000000.10101000.00000001.00100101
255.255.255.0 → 11111111.11111111.11111111.00000000
Wynik AND → 11000000.10101000.00000001.00000000
→ 192.168.1.0 (adres sieci)
Inżynierowie sieci rutynowo przeliczają między dziesiętnym (notacja IP), binarnym (matematyka podsieci), a niekiedy szesnastkowym (przechwyty pakietów). Nasz Konwerter systemów liczbowych obsługuje każdy oktet osobno, jeśli wolisz wizualną kontrolę.
5. Odczytywanie skrótów hash i UUID
Skrót MD5 taki jak d41d8cd98f00b204e9800998ecf8427e to 32 znaki szesnastkowe, reprezentujące 16 bajtów (128 bitów). Każda para cyfr szesnastkowych to jeden bajt.
UUID podąża za schematem 8-4-4-4-12 cyfr szesnastkowych:
550e8400-e29b-41d4-a716-446655440000
To 32 cyfry szesnastkowe oddzielone myślnikami — te same 128 bitów, tylko inaczej sformatowane. Nibble wersji znajduje się na pozycji 13 (cyfra 4 w 41d4 oznacza UUID v4).
Generuj skróty hash w naszym Generatorze MD5 i SHA hash lub twórz UUID-y w naszym Generatorze UUID — oba zwracają wynik szesnastkowy, który odwzorowuje się bezpośrednio na omawiane tu reprezentacje binarne.
Poza podstawą 16: base 36, base 64 i systemy niestandardowe
Standardowa czwórka pokrywa większość pracy, lecz w wyspecjalizowanych kontekstach pojawia się jeszcze kilka innych podstaw.
System o podstawie 36 — zwarty zapis alfanumeryczny
System o podstawie 36 wykorzystuje wszystkie 10 cyfr i 26 liter (A-Z), co daje najbardziej zwartą możliwą reprezentację alfanumeryczną nieczułą na wielkość liter. Skracacze URL go uwielbiają — identyfikatory filmów na YouTube, krótkie linki i zwarte klucze bazodanowe często korzystają z systemu 36.
(1000000).toString(36) // 'lfls'
parseInt('lfls', 36) // 1000000
Liczba dziesiętna 1 000 000 kompresuje się do zaledwie czterech znaków. Dla krótkich, bezpiecznych w URL identyfikatorów trudno o lepsze rozwiązanie.
Base64 — kodowanie danych (nie system liczbowy)
Base64 wygląda jak kolejny system liczbowy, ale służy innemu celowi. Zamiast reprezentować wartość liczbową w systemie pozycyjnym, Base64 koduje dowolne dane binarne (obrazy, pliki, JWT token) jako tekst ASCII. Wykorzystuje znaki A-Z, a-z, 0-9, + oraz / — łącznie 64 symbole.
Matematyka jest tu inna niż przy konwersji systemów liczbowych. Base64 przetwarza wejście w blokach 3-bajtowych (24-bitowych) i generuje cztery 6-bitowe znaki. To schemat kodowania, a nie system liczbowy.
Do kodowania i dekodowania danych Base64 użyj naszego Kodera i dekodera Base64.
Dowolne podstawy (2-36) i kiedy się pojawiają
Kilka innych podstaw pojawia się w praktyce:
- Podstawa 12 (dwunastkowa): czas (12 godzin), ilości (tuzin). Niektórzy matematycy argumentują, że podstawa 12 byłaby lepsza od dziesiętnej do codziennego użytku, ponieważ 12 ma więcej dzielników.
- Podstawa 60 (sześćdziesiątkowa): czas (60 sekund, 60 minut) i kąty (360°). Dziedzictwo matematyki babilońskiej.
- Podstawa 32: kodowanie Crockford’s Base32 dla czytelnych dla człowieka identyfikatorów (wyklucza znaki niejednoznaczne, takie jak I, L, O). Wykorzystywana również w geohashingu.
Nasz Konwerter systemów liczbowych obsługuje dowolną całkowitą podstawę od 2 do 36.
Operacje bitowe a konwersja systemów liczbowych
Zrozumienie zapisu binarnego to nie tylko konwersja liczb — to fundament operacji bitowych pojawiających się w programowaniu systemowym, tworzeniu gier i systemach uprawnień.
const READ = 0b100; // 4
const WRITE = 0b010; // 2
const EXEC = 0b001; // 1
// Łączenie uprawnień przez OR
const perms = READ | WRITE; // 0b110 = 6
// Sprawdzenie konkretnego uprawnienia przez AND
(perms & READ) !== 0 // true — ma odczyt
(perms & EXEC) !== 0 // false — nie ma wykonania
// Przełączenie uprawnienia przez XOR
perms ^ WRITE // 0b100 = 4 — zapis usunięty
// Operacje przesunięcia
1 << 3 // 0b1000 = 8 (1 przesunięte w lewo o 3)
0xFF >> 4 // 0b00001111 = 15 (przesunięcie w prawo o 4 = dzielenie przez 16)
Flagi funkcji, rejestry sprzętowe, protokoły sieciowe i programowanie graficzne — wszystko to opiera się na operacjach bitowych. Gdy zapis binarny zaskoczy, manipulacja bitami zaczyna się czytać jak czysta logika — bez magii.
FAQ
Jakie są cztery główne systemy liczbowe używane w programowaniu?
Dwójkowy (podstawa 2), ósemkowy (podstawa 8), dziesiętny (podstawa 10) i szesnastkowy (podstawa 16). System dwójkowy odzwierciedla fizyczną postać danych w sprzęcie. Ósemkowy odwzorowuje uprawnienia plików w Uniksie. Dziesiętny jest domyślnym systemem dla człowieka. Hex kompresuje zapis binarny do czytelnej formy — każda cyfra szesnastkowa to dokładnie 4 bity.
Jak przeliczyć liczbę z systemu dwójkowego na szesnastkowy?
Pogrupuj cyfry binarne po cztery od prawej do lewej, dopełniając skrajnie lewą grupę zerami w razie potrzeby. Odwzoruj każdą grupę: 0000=0, 0001=1, …, 1010=A, …, 1111=F. Przykład: binarnie 10101111 → grupy 1010 1111 → hex AF. Działa to dlatego, że 16 = 2⁴.
Jak przeliczyć liczbę szesnastkową na dziesiętną?
Pomnóż każdą cyfrę szesnastkową przez 16 podniesione do potęgi równej numerowi pozycji (od prawej = 0), a następnie zsumuj. A=10, B=11, C=12, D=13, E=14, F=15. Przykład: hex FF = 15×16¹ + 15×16⁰ = 240 + 15 = 255. W kodzie: JavaScript parseInt('FF', 16), Python int('FF', 16).
Dlaczego programiści używają systemu szesnastkowego zamiast dwójkowego?
Hex jest zwarty. Każda cyfra szesnastkowa odwzorowuje się na dokładnie 4 bity, więc 11111111 00001010 w zapisie binarnym staje się FF0A w hex — znacznie krócej i łatwiej przeskanować wzrokiem. Hex to standard dla adresów pamięci, kolorów CSS (#FF5733), adresów MAC, wyników hash i formatowania UUID.
Czym jest nibble i dlaczego ma znaczenie przy konwersji do hex?
Nibble to 4 bity binarne — połowa bajtu. Jeden nibble odwzorowuje się na dokładnie jedną cyfrę szesnastkową, dlatego konwersja binarny-hex sprowadza się do prostego odczytu nibble po nibble. Jeden bajt = dwa nibble = dwie cyfry szesnastkowe. To czyste 4-bitowe odwzorowanie jest powodem, dla którego hex stał się standardem reprezentacji danych na poziomie bajtów.
Dlaczego uprawnienia plików w Uniksie zapisuje się ósemkowo?
Trzy bity uprawnień (read=4, write=2, execute=1) na grupę, trzy grupy (właściciel, grupa, pozostali). Ponieważ 2³ = 8, każda grupa trzech bitów odwzorowuje się na jedną cyfrę ósemkową. 755 oznacza właściciel=7 (rwx), grupa=5 (r-x), pozostali=5 (r-x). System ósemkowy jest naturalną podstawą dla grupowań 3-bitowych.
Jak obsłużyć w JavaScripcie liczby większe niż 2⁵³?
Skorzystaj z BigInt. Dopisz n do literału lub użyj konstruktora BigInt(): BigInt('0xFFFFFFFFFFFFFFFF').toString(2) zwróci pełny 64-bitowy ciąg binarny. Standardowy Number traci precyzję powyżej 9 007 199 254 740 991 (2⁵³ - 1). Nasz Konwerter systemów liczbowych wykorzystuje BigInt wewnętrznie, więc obsługuje liczby dowolnej wielkości bez utraty precyzji.
Jak przeliczyć liczbę szesnastkową na dwójkową?
Zastąp każdą cyfrę szesnastkową jej 4-bitowym odpowiednikiem binarnym, korzystając z tej samej tabeli nibble w odwrotną stronę: 0=0000, 1=0001, …, A=1010, …, F=1111. Przykład: hex AF → A (1010) + F (1111) → binarnie 10101111. W kodzie: JavaScript parseInt('AF', 16).toString(2) lub Python bin(int('AF', 16))[2:].
Dlaczego kolory hex w CSS mają niekiedy 3, 6 lub 8 cyfr?
Wszystkie trzy formy odwzorowują ten sam model RGB, ale kodują różną precyzję i wartość alfa. 3-cyfrowa #F0A to skrót, który rozwija się do #FF00AA (każda cyfra zdublowana). 6-cyfrowa #FF00AA to standardowa forma RGB — dwie cyfry szesnastkowe na kanał. 8-cyfrowa #FF00AA80 dodaje kanał alfa jako czwarty bajt, gdzie 80 (dziesiętnie 128) to ~50% nieprzezroczystości. Współczesne przeglądarki akceptują wszystkie trzy; projektanci wybierają najkrótszą formę zachowującą zamierzony efekt.