
Systemy liczbowe i operacje bitowe — Kompletny przewodnik
Poznaj konwersje podstaw, maski bitowe, uzupełnienie do dwóch, zakresy liczb i operacje na rejestrach na przykładach systemów wbudowanych.
Przykłady można odtworzyć w konwerterze systemów liczbowych. System binarny, dziesiętny, szesnastkowy i ósemkowy przedstawiają tę samą liczbę innymi cyframi. Binarny opisuje stany logiczne i rejestry, szesnastkowy skraca zapis bajtów i adresów, dziesiętny ułatwia odczyt pomiarów, a ósemkowy grupuje bity po trzy, np. w maskach uprawnień.
1. Podstawy i zapis pozycyjny
Podstawa 2 używa cyfr 0–1, podstawa 8 cyfr 0–7, podstawa 10 cyfr 0–9, a podstawa 16 także A–F, gdzie A = 10 i F = 15. Dla cyfr dᵢ w podstawie b: N = Σ dᵢ × bⁱ, zaczynając od i = 0 po prawej. Zera wiodące nie zmieniają wartości, ale mogą wskazywać szerokość rejestru.
| DEC | BIN | HEX | OCT |
|---|---|---|---|
| 0 | 0000 | 0 | 0 |
| 1 | 0001 | 1 | 1 |
| 2 | 0010 | 2 | 2 |
| 3 | 0011 | 3 | 3 |
| 4 | 0100 | 4 | 4 |
| 5 | 0101 | 5 | 5 |
| 6 | 0110 | 6 | 6 |
| 7 | 0111 | 7 | 7 |
| 8 | 1000 | 8 | 10 |
| 9 | 1001 | 9 | 11 |
| 10 | 1010 | A | 12 |
| 11 | 1011 | B | 13 |
| 12 | 1100 | C | 14 |
| 13 | 1101 | D | 15 |
| 14 | 1110 | E | 16 |
| 15 | 1111 | F | 17 |
2. Konwersje krok po kroku
Binarny na dziesiętny: 10101010₂ = 1×128 + 0×64 + 1×32 + 0×16 + 1×8 + 0×4 + 1×2 + 0×1 = 170₁₀. Sumujemy wagi ustawionych pozycji.
Dziesiętny na binarny: dzielimy wielokrotnie przez 2 i zapisujemy reszty. Dla 13: 13 = 2×6+1; 6 = 2×3+0; 3 = 2×1+1; 1 = 2×0+1. Reszty odczytane od dołu dają 1101. Podobnie 255₁₀ = 11111111₂ = FF₁₆ = 377₈.
Binarny na szesnastkowy: grupujemy po cztery od prawej i uzupełniamy zerami tylko lewą grupę: 1010 1011 1100 1101₂ = ABCD₁₆. Cztery bity odpowiadają jednej cyfrze, ponieważ 16 = 2⁴.
Szesnastkowy na binarny: każdą cyfrę zastępujemy czterema bitami: 0x2F → 0010 1111₂ → 47₁₀. Wielkość liter nie zmienia wartości.
Ósemkowy: grupujemy po trzy, ponieważ 8 = 2³: 11111111₂ → 011 111 111₂ = 377₈. Odwrotnie: 17₈ → 001 111₂ = 15₁₀. Pozycyjnie 377₈ = 3×8² + 7×8 + 7 = 255. Z dziesiętnego na ósemkowy przechodzimy przez wielokrotne dzielenie przez 8.
3. Arytmetyka i dokładne liczby całkowite
Przykłady: 0x0F + 0b1 = 16, 20 − 7 = 13, 0o7 × 0x3 = 21. Dodawanie binarne przenosi jedynkę, gdy suma w kolumnie wynosi dwa: 0111 + 0001 = 1000.
Narzędzie używa BigInt przy konwersji i obliczeniach, także powyżej 2⁵³ − 1. Dzielenie całkowite obcina w kierunku zera: −7 ÷ 3 = −2. % zwraca resztę o znaku dzielnej, a nie zawsze nieujemne modulo euklidesowe: −7 % 3 = −1. Dla niezerowego b zachodzi a = (a / b) × b + (a % b). Dzielenie i reszta z dzielenia przez zero są błędami.
4. AND, OR, XOR i NOT
AND zachowuje bity ustawione w obu wejściach; OR ustawia bit obecny w co najmniej jednym; XOR ustawia różniące się pozycje; NOT odwraca wszystkie bity w wybranej szerokości. Każda kolumna działa niezależnie.
| A | B | A AND B | A OR B | A XOR B | NOT A |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 1 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 | 0 |
| 1 | 1 | 1 | 1 | 0 | 0 |
Dla ośmiu bitów: 11111111 & 00001111 = 00001111 (15); 10100000 | 00001111 = 10101111 (175); 10101010 ^ 11111111 = 01010101 (85). NOT z 00001111 bez znaku daje 11110000 (240). Auto nie ma skończonej maski: ~15 = −16, ponieważ ~x = −x − 1.
5. Liczby ze znakiem i uzupełnienie do dwóch
Bez znaku wartość wynosi Σ bᵢ2ⁱ, a zakres 0 … 2ʷ−1. W uzupełnieniu do dwóch najstarszy bit ma wagę −2ʷ⁻¹, a zakres wynosi −2ʷ⁻¹ … 2ʷ⁻¹−1. Gdy ten bit jest ustawiony, odejmujemy 2ʷ od interpretacji bez znaku.
Dla ośmiu bitów: FF = 255 − 256 = −1, 80 = 128 − 256 = −128. Aby zakodować −5, odwracamy 00000101 do 11111010 i dodajemy jeden: 11111011 = FB. Dla szesnastu bitów FFFF oznacza −1. Uzupełnienie do dwóch jest binarną reprezentacją zależną od szerokości, a nie osobną podstawą.
| Bity | Bez znaku | Ze znakiem |
|---|---|---|
| 8 | 0 … 255 | −128 … 127 |
| 16 | 0 … 65535 | −32768 … 32767 |
| 32 | 0 … 4294967295 | −2147483648 … 2147483647 |
| 64 | 0 … 18446744073709551615 | −9223372036854775808 … 9223372036854775807 |
DEC oznacza wartość matematyczną. Nieujemne BIN/HEX/OCT przy stałej szerokości są wzorcami bitów: HEX FF ze znakiem na 8 bitach daje DEC −1, natomiast DEC 255 jest odrzucane. Ujemne wejścia muszą mieścić się w zakresie matematycznym. Żadne wejście nie jest po cichu obcinane. Wyjścia niedziesiętne są dopełniane zerami; pierwsza cyfra ósemkowa może zawierać do dwóch nieużywanych starszych bitów.
Auto nie narzuca szerokości ani zakresu bez znaku. Ujemne wartości pokazuje jako znak i moduł. Widok obejmuje najwyżej 128 najmłodszych bitów modułu; konwersje i kopie zachowują całą liczbę.
6. Przesunięcia i przepełnienie
Przesunięcie w lewo o k bitów mnoży bez ograniczenia szerokości przez 2ᵏ: 0x01 << 4 = 0x10 = 16. Przy stałej szerokości stosowana jest maska 2ʷ−1. Na ośmiu bitach bez znaku 0x80 << 1 ma dokładny wynik 256, a zapisany 0, z ostrzeżeniem. Ze znakiem 0x40 << 1 daje −128 z ostrzeżeniem, ponieważ dokładne 128 jest poza zakresem.
Logiczne przesunięcie w prawo wstawia zera: FF >> 1 = 7F = 127 bez znaku. Arytmetyczne powiela znak: FF >> 1 = FF = −1, 80 >> 1 = C0 = −64 ze znakiem na ośmiu bitach. Dla ujemnych zaokrągla w dół: −3 >> 1 = −2, podczas gdy −3 / 2 = −1.
B jest zawsze nieujemną dziesiętną liczbą przesunięć od 0 do 65536, niezależnie od poprzedniej podstawy i szerokości. Limit ogranicza pracę jednego obliczenia, a nie precyzję danych. Liczba przesunięć nie jest redukowana modulo 32 ani modulo szerokość słowa. Przesunięcie ośmiobitowej liczby bez znaku w prawo o 8 daje 0. Przepełnienie arytmetyczne, np. 255 + 1 bez znaku lub −128 / −1 ze znakiem na ośmiu bitach, jest odrzucane z podaniem dokładnego wyniku DEC. Auto stosuje nieograniczoną semantykę BigInt ze znakiem.
7. Rejestry STM32, maski i flagi
W STM32F407 rejestr wejściowy GPIO udostępnia stany pinów. Po skonfigurowaniu zegara i peryferium nagłówek urządzenia CMSIS umożliwia przykładowo:
uint32_t snapshot = GPIOA->IDR;
uint32_t pin5 = (snapshot >> 5u) & 1u;
uint32_t field = (snapshot >> 4u) & 0x0Fu;
GPIOA->BSRR = 1u << 5u;
Dla snapshot = 0xB0, pin5 wynosi 1, a bity 7:4 tworzą 0xB = 11. Zapis BSRR ustawia bit wyjściowy 5 bez programowej operacji odczyt-modyfikacja-zapis ODR; tryb pinu nadal określa zachowanie na zewnątrz. Sprawdź instrukcję konkretnego układu, w tym zegary, bity zarezerwowane i pola kasowane zapisem jedynki. Pojedyncza kopia zapobiega łączeniu kolejnych odczytów różnych stanów.
Operacje na lokalnej zmiennej bez znaku:
uint32_t flags = 0u;
uint32_t mask = 1u << 3u;
flags |= mask;
flags &= ~mask;
flags ^= mask;
uint32_t active = (flags & mask) != 0u;
Maska 0x08 wybiera bit 3. OR go ustawia, AND z dopełnieniem kasuje, XOR odwraca, a końcowe wyrażenie sprawdza. Odczyt-modyfikacja-zapis nie jest automatycznie atomowy dla pamięci współdzielonej lub rejestrów. Użyj udokumentowanych mechanizmów lub odpowiedniej synchronizacji.
8. CAN, UART, SPI, ADC i FPGA
Bajty 0x12 i 0x34 tworzą według protokołu big endian (0x12 << 8) | 0x34 = 0x1234 = 4660; interpretacja little endian daje 0x3412 = 13330. Pola CAN definiuje specyfikacja wiadomości lub DBC. Ramkowanie UART i kolejność bitów SPI nie ustalają samodzielnie kolejności bajtów wielobajtowej wartości aplikacji. Zobacz UART i SPI.
Dla 12-bitowego ADC bez znaku 0xABC = 2748 mieści się w 0–4095. Przybliżenie wyświetlania łączące końce zakresu przy Vref = 3,3 V daje 2748 × 3,3 / 4095 ≈ 2,2145 V. Nie jest to dokładna charakterystyka kwantyzacji: idealny krok wynosi 3,3/4096 V, a rzeczywisty transfer zależy od ADC. Dane ze znakiem mogą używać uzupełnienia do dwóch lub kodu z przesunięciem. Sprawdź kodowanie i wyrównanie, a następnie użyj kalkulatora ADC/DAC.
W FPGA i mikrokontrolerach jawnie deklaruj szerokość i znak. W SystemVerilog 8'hFF to ośmiobitowy wzorzec bez znaku, a 8'shFF oznacza −1 ze znakiem. Literały bez szerokości i promocje typów mogą zmieniać wynik. Maskowanie kalkulatora nie odtwarza wszystkich reguł C/C++ i HDL.
9. Często zadawane pytania
Jak zamienić liczbę binarną na szesnastkową?
Podziel bity od prawej na grupy po cztery i przypisz każdej cyfrę 0–F. Na przykład 1111 0000 daje F0. Lewą grupę uzupełnij zerami w razie potrzeby.
Czym różnią się liczby całkowite ze znakiem i bez znaku?
Bez znaku wszystkie bity tworzą wartość nieujemną. W uzupełnieniu do dwóch najstarszy bit ma wagę ujemną. FF na ośmiu bitach to 255 bez znaku lub −1 ze znakiem.
Jak działa uzupełnienie do dwóch?
Dla wartości ujemnej na w bitach dodaj ją do 2ʷ. Równoważnie odwróć bity dodatniego modułu i dodaj jeden w wybranej szerokości.
Co to jest bitowa operacja XOR?
Daje jeden tam, gdzie bity wejściowe się różnią. XOR z maską odwraca wybrane pozycje: AA XOR FF daje 55.
Jak wyodrębnić bity z rejestru?
Przesuń pole w prawo i wykonaj AND z maską jego szerokości. Dla bitów 7:4: (reg >> 4) & 0x0F. Uwzględnij skutki odczytu rejestru sprzętowego.
Dlaczego FF czasami oznacza −1?
Interpretacja zależy od szerokości. FF na ośmiu bitach ma ustawiony bit znaku, a 00FF na szesnastu bitach oznacza +255.