Skip to content
Powrót do bloga
Poradniki

Operacje bitowe w praktyce: AND, OR, XOR, przesunięcia i maski

Operacje bitowe na konkretach: AND, OR, XOR, przesunięcia, U2, maski bitowe i flagi funkcji — z kodem w JS, Pythonie, Go i C.

17 min czytania

Operacje bitowe w praktyce: AND, OR, XOR, przesunięcia, maski

Otwierasz starszą migrację PostgreSQL i widzisz permissions & 0b100. Kolega wdraża system flag funkcji, który upakowuje 32 wartości logiczne w pojedynczą liczbę całkowitą. Kalkulator podsieci Kubernetes zwraca 192.168.1.0/24 i trzeba w kodzie wyłuskać adres sieci. Trzy sytuacje, jedna leżąca u podstaw umiejętność: operacje bitowe.

Większość programistów warstwy aplikacyjnej nigdy nie sięga po & ani ^ w aplikacji webowej — aż do momentu, gdy nagle musi. Ten przewodnik prowadzi przez sześć operatorów bitowych, uzupełnienie do dwóch (U2), dziewięć wzorców wartych zapamiętania oraz pułapki specyficzne dla poszczególnych języków, które potrafią zaboleć (zwłaszcza w JavaScripcie). Kod jest w JS, Pythonie, Go i C, a każdy przykład można uruchomić.

Otwórz nasz konwerter systemów liczbowych w drugiej karcie. Kilka sekcji zachęca, by wpisać liczbę i obserwować, jak zmienia się układ bitów.

Dlaczego operacje bitowe nadal mają znaczenie w 2026 roku

Języki wysokiego poziomu nie sprawiły, że operacje bitowe stały się przestarzałe. Po prostu ukryły miejsce, w którym te operacje się odbywają. Oto kilka miejsc, w których już dziś z nich korzystasz, niezależnie od tego, czy zdajesz sobie z tego sprawę:

  • Bezpieczeństwo na poziomie wiersza w PostgreSQL używa bitmapy uprawnień ACL (SELECT, INSERT, UPDATE, DELETE, …) upakowanych w liczbę całkowitą.
  • Linux capabilities zastępują dawny model „root albo nic” ponad 40 bitami uprawnień, które łączysz operatorem |.
  • Nagłówki algorytmów JWT kodują algorytm hash w niewielkim polu, w którym porównanie na poziomie bitów jest powszechne w warstwie biblioteki.
  • Snowflake, ULID i UUIDv7 upakowują timestamp, identyfikator maszyny i numer sekwencyjny w pojedynczą liczbę 64- lub 128-bitową, używając przesunięć w lewo.
  • Redisowe BITCOUNT i BITOP udostępniają prymitywy bitowe wprost kodowi aplikacji do estymacji liczności i bucketingu w testach A/B.
  • Przetwarzanie obrazu odczytuje 32-bitowe piksele RGBA i wyłuskuje kanały operatorami & oraz >>.

Operacje bitowe pozostają O(1) na poziomie instrukcji CPU. Gdy upakowujesz 32 wartości logiczne w jedną liczbę całkowitą, oszczędzasz 31 bajtów pamięci, a (co ważniejsze) możesz sprawdzić „czy ustawiona jest którakolwiek z tych 32 flag” pojedynczym testem != 0.

Podstawy systemu dwójkowego, które trzeba znać

Ten przewodnik zakłada, że wiesz już, jak działa system dwójkowy. Jeśli potrzebujesz przypomnienia, przeczytaj najpierw nasz przewodnik po konwersji systemów liczbowych i wróć tutaj.

Krótkie sprawdzenie słownictwa, zanim zaczniemy:

  • Bit to 0 albo 1.
  • Nibble to 4 bity (jedna cyfra szesnastkowa).
  • Bajt to 8 bitów.
  • Słowo to zwykle 32 lub 64 bity, zależnie od CPU.

Liczby całkowite w większości języków występują w stałych szerokościach: 8, 16, 32, 64. Szerokość ma duże znaczenie dla operacji bitowych, ponieważ przesunięcia mogą wypchnąć bity poza krawędź, a bit znaku znajduje się na skrajnie lewej pozycji liczb całkowitych ze znakiem.

Wypróbuj teraz. Otwórz konwerter systemów liczbowych, wpisz 170 jako liczbę dziesiętną i spójrz na wynik w postaci dwójkowej. Zobaczysz 10101010 — naprzemienny wzorzec, do którego wrócimy poniżej kilkukrotnie.

Sześć operatorów bitowych

Każdy popularny język udostępnia te same sześć operatorów, czasem z drobnymi różnicami składniowymi. Symbole &, |, ^, ~, <<, >> działają w JavaScripcie, Pythonie, Go, Ruście, C, C++, Javie i C# bez zmian. JavaScript dokłada jeszcze jeden: >>>, czyli przesunięcie w prawo bez znaku.

AND (&): filtr bitów

Bit wynikowy jest równy 1 tylko wtedy, gdy oba bity wejściowe są równe 1.

ABA & B
000
010
100
111

O AND warto myśleć jak o bramce: przeżywają tylko bity ustawione w obu operandach. Najczęstszym zastosowaniem jest maskowanie — zachowanie wybranych bitów i wyzerowanie pozostałych.

// Extract the low 4 bits (the rightmost nibble)
const value = 0b11010110;   // 214
const low4  = value & 0x0F; // 0b00000110 = 6

// Check if a number is odd
const isOdd = (n) => (n & 1) === 1;
isOdd(7);  // true
isOdd(42); // false
# Same in Python
value = 0b11010110
low4 = value & 0x0F  # 6

def is_odd(n):
    return (n & 1) == 1

OR (|): ustawianie bitu

Bit wynikowy jest równy 1, jeśli którykolwiek bit wejściowy jest równy 1.

ABA | B
000
011
101
111

OR łączy flagi. Jeśli READ = 1, WRITE = 2, EXECUTE = 4, to READ | WRITE daje 3 z włączonymi obiema uprawnieniami.

const READ  = 0b001;
const WRITE = 0b010;
const EXEC  = 0b100;

const rw = READ | WRITE;  // 0b011 = 3
READ, WRITE, EXEC = 0b001, 0b010, 0b100
rw = READ | WRITE  # 3

XOR (^): przełącznik bitu

Bit wynikowy jest równy 1, jeśli bity wejściowe różnią się.

ABA ^ B
000
011
101
110

XOR ma trzy własności algebraiczne, które stoją za niektórymi z najsprytniejszych sztuczek w informatyce:

  • a ^ a = 0: cokolwiek XOR-owane samo ze sobą się znosi.
  • a ^ 0 = a: XOR z zerem jest tożsamością.
  • a ^ b ^ a = b: XOR jest swoją własną odwrotnością.

Ostatnia własność tłumaczy, dlaczego XOR pojawia się w kontroli parzystości, w szyfrach strumieniowych i w słynnym pytaniu rekrutacyjnym o „znajdowanie jedynego niezdublowanego elementu w tablicy”.

// Find the one unique number in an array where every other number appears twice
const findUnique = (arr) => arr.reduce((a, b) => a ^ b, 0);
findUnique([4, 1, 2, 1, 2]);  // 4
from functools import reduce
from operator import xor
find_unique = lambda arr: reduce(xor, arr, 0)
find_unique([4, 1, 2, 1, 2])  # 4

NOT (~): inwerter bitów

Jednoargumentowy ~ odwraca każdy bit: 0 staje się 1, 1 staje się 0.

~0b00001111  // -16  (JavaScript coerces to 32-bit signed)
~5           // -6
~5  # -6
// Go uses ^ as unary bitwise NOT, watch out
var x int8 = 5
fmt.Println(^x)  // -6

Wynik ~5 to -6 w każdym popularnym języku i to zaskakuje początkujących. Powodem jest uzupełnienie do dwóch (U2), które omawiamy w następnej sekcji. Na razie wystarczy wiedzieć, że ~x równa się -(x + 1) w każdym języku stosującym U2 do reprezentacji liczb ujemnych (czyli we wszystkich).

Przesunięcie w lewo (<<): mnożnik potęg dwójki

x << n przesuwa każdy bit x w lewo o n pozycji, dosypując zera z prawej strony. Matematycznie odpowiada to mnożeniu przez 2ⁿ.

1 << 0   // 1   (2^0)
1 << 1   // 2   (2^1)
1 << 3   // 8   (2^3)
1 << 10  // 1024 (2^10 = 1 KiB)

// Building bit flags
const FLAG_ADMIN    = 1 << 0;
const FLAG_EDITOR   = 1 << 1;
const FLAG_REVIEWER = 1 << 2;

Wygodna własność 1 << n polega na tym, że tworzy liczbę z pojedynczym bitem ustawionym na pozycji n. Ten bit pełni rolę flagi.

Uwaga na przepełnienie. W JavaScripcie 1 << 31 daje -2147483648 (a nie 2147483648), bo operatory bitowe JavaScriptu działają na 32-bitowych liczbach całkowitych ze znakiem.

Przesunięcie w prawo (>> vs >>>): dzielenie czy dosypywanie zer?

Przesunięcie w prawo przenosi bity w prawo. Pytanie brzmi: co wypełnia opuszczone pozycje skrajnie z lewej.

  • >> (arytmetyczne przesunięcie w prawo) zachowuje bit znaku. Liczby ujemne pozostają ujemne.
  • >>> (logiczne przesunięcie w prawo, bez znaku) wypełnia zerami. Tylko JavaScript ma to jako osobny operator.
-8 >> 1   // -4   (sign bit preserved)
-8 >>> 1  // 2147483644  (sign bit treated as a data bit)

8 >> 1    // 4
8 >> 2    // 2

W C to, czy >> jest arytmetyczne czy logiczne dla typów ze znakiem, jest zależne od implementacji. Większość kompilatorów stosuje wariant arytmetyczny, ale nie należy na tym polegać bez sprawdzenia. Go wymaga, by wartość przesunięcia była nieujemną liczbą całkowitą, i jawnie traktuje typy ze znakiem oraz bez znaku. Python nie ma >>>, ponieważ nie ma liczb całkowitych o stałej szerokości.

Uzupełnienie do dwóch (U2): jak komputery reprezentują liczby ujemne

Skoro bity to tylko 0 i 1, jak zakodować -5? Świat ustalił odpowiedź w latach 60. — uzupełnienie do dwóch (U2) — i każdy nowoczesny CPU z niej korzysta.

Naiwne podejście (rezerwacja jednego bitu na znak) ma dwa problemy. Po pierwsze, otrzymujesz zarówno +0, jak i -0, co jest niewygodne. Po drugie, układy dodawania i odejmowania musiałyby sprawdzać bit znaku, co komplikuje sprzęt. U2 rozwiązuje oba.

Reguła jest krótka:

  1. Weź dodatnią reprezentację dwójkową.
  2. Odwróć każdy bit (to „uzupełnienie do jedności”).
  3. Dodaj 1.

Przykład: kodowanie -5 w 8-bitowym uzupełnieniu do dwóch (U2):

 5 w systemie dwójkowym:   0000 0101
 odwróć wszystkie bity:    1111 1010   (to jest -6 w U2!)
 dodaj 1:                  1111 1011   ← to jest -5

Sprawdź w naszym konwerterze: wpisz 251 (dziesiętnie) w konwerterze systemów liczbowych z bazą 10 — wynik dwójkowy to 11111011. W kontekście 8-bitowym ze znakiem 11111011 to -5. W kontekście 8-bitowym bez znaku ten sam układ bitów to 251. Bity są identyczne, różni się interpretacja.

To wyjaśnia wcześniejszą niespodziankę z ~5 = -6. Bitowe NOT odwraca bity, dając uzupełnienie do jedności. Uzupełnienie do dwóch to uzupełnienie do jedności plus 1. Stąd:

~x   = -(x + 1)        // tożsamość w każdym języku z U2
~5   = -6
~(-3) = 2

Dla n-bitowych liczb całkowitych ze znakiem reprezentowalny zakres to od -2ⁿ⁻¹ do 2ⁿ⁻¹ − 1. 8-bitowa liczba całkowita ze znakiem obejmuje -128 do 127. 32-bitowa liczba całkowita ze znakiem obejmuje mniej więcej od -2,1 miliarda do +2,1 miliarda.

Niezbędne wzorce manipulacji bitami

Tych dziewięć wzorców pokrywa może 95% manipulacji bitami, jaką w życiu napiszesz. Zapamiętaj je, a będziesz je rozpoznawać wszędzie w kodzie systemowym.

Ustawienie bitu: x | (1 << n)

Włącz bit n, pozostałe bity zostaw bez zmian.

let flags = 0b0100;
flags = flags | (1 << 0);  // 0b0101

Wyzerowanie bitu: x & ~(1 << n)

Wyłącz bit n, pozostałe bity zostaw bez zmian. ~(1 << n) to maska z każdym bitem ustawionym poza bitem n.

let flags = 0b0111;
flags = flags & ~(1 << 1);  // 0b0101

Przełączenie bitu: x ^ (1 << n)

Odwróć bit n niezależnie od jego bieżącego stanu.

let flags = 0b0100;
flags = flags ^ (1 << 2);  // 0b0000
flags = flags ^ (1 << 2);  // 0b0100 again

Sprawdzenie bitu: (x >> n) & 1

Zwraca 1, jeśli bit n jest ustawiony, w przeciwnym razie 0. Forma równoważna: (x & (1 << n)) !== 0.

const flags = 0b0101;
const isBit2Set = (flags >> 2) & 1;  // 1

Wyizolowanie najniższego ustawionego bitu: x & -x

Daje wartość, w której zachowany jest tylko skrajnie prawy bit 1 z x. Sztuczka działa, bo -x w U2 to ~x + 1, co odwraca każdy bit aż do najniższego ustawionego włącznie.

const x = 0b10110100;
const lowest = x & -x;  // 0b00000100 = 4

To podstawowy trik wewnątrz drzew Fenwicka (Binary Indexed Trees) używanych do prefiksowych sum w O(log n).

Liczenie ustawionych bitów (popcount)

Zliczanie liczby bitów 1 w liczbie całkowitej. Większość języków ma już natywną funkcję:

// JavaScript (BigInt or manual)
const popcount = (n) => {
  let count = 0;
  while (n) { count += n & 1; n >>>= 1; }
  return count;
};
popcount(0b10110100);  // 4
# Python 3.10+
(0b10110100).bit_count()  # 4
// Go
import "math/bits"

bits.OnesCount(0b10110100) // 4

Zamiana XOR-em bez zmiennej tymczasowej

Klasyczna sztuczka imprezowa: zamiana dwóch liczb całkowitych miejscami bez trzeciej zmiennej. Nigdy nie używaj tego na produkcji (jest wolniejsza niż zmienna tymczasowa i psuje się, gdy a i b wskazują tę samą lokację w pamięci), ale warto ją rozumieć.

let a = 5, b = 9;
a = a ^ b;  // a = 5 ^ 9
b = a ^ b;  // b = (5 ^ 9) ^ 9 = 5
a = a ^ b;  // a = (5 ^ 9) ^ 5 = 9
// a = 9, b = 5

Wykrycie potęgi dwójki: (x & (x - 1)) === 0

Potęga dwójki ma dokładnie jeden ustawiony bit. Odjęcie 1 wyłącza ten bit i ustawia każdy bit niższy. Operacja AND daje zero tylko dla potęg dwójki (oraz dla 0, więc zabezpiecz x > 0).

const isPow2 = (x) => x > 0 && (x & (x - 1)) === 0;
isPow2(16);  // true
isPow2(17);  // false

Szybkie sprawdzenie nieparzystości: x & 1

Szybsze niż x % 2 w niektórych językach, identyczne w innych po optymalizacji kompilatora. Warte zachodu w gorących pętlach albo gdy czytelność nie ma znaczenia.

const isOdd = (x) => (x & 1) === 1;

Maski bitowe w prawdziwym kodzie

Powyższe wzorce pojawiają się w kodzie produkcyjnym każdego dnia. Oto cztery miejsca, w których je spotkasz.

Flagi funkcji w 32 wartościach logicznych

Zamiast 32-polowej struktury wartości logicznych, upakuj je w jedną liczbę całkowitą:

const FLAGS = {
  DARK_MODE:      1 << 0,
  NEW_NAV:        1 << 1,
  AI_SUGGESTIONS: 1 << 2,
  BETA_EDITOR:    1 << 3,
  // ... up to 1 << 31
};

let userFlags = 0;
userFlags |= FLAGS.DARK_MODE | FLAGS.AI_SUGGESTIONS;  // opt in

if (userFlags & FLAGS.AI_SUGGESTIONS) {
  showSuggestions();
}

userFlags &= ~FLAGS.DARK_MODE;  // opt out

To upycha 32 wartości logiczne w 4 bajtach i pozwala odpytać dowolny podzbiór pojedynczym AND. Bazy danych uwielbiają ten wzorzec, bo zamiast 32 kolumn jest jedna.

Uprawnienia plików w Uniksie

chmod 755 to operacja bitowa. Trzy cyfry ósemkowe odpowiadają trzem trójkom bitów:

7 = 111  (właściciel: rwx)
5 = 101  (grupa:      r-x)
5 = 101  (pozostali:  r-x)

Wypróbuj: otwórz konwerter systemów liczbowych, ustaw bazę źródłową na ósemkową, wpisz 755 i spójrz na wynik dwójkowy 111101101. Dokładnie tak system plików przechowuje pole uprawnień.

Ustawienie samego „zapisu dla grupy”:

const perms = 0o755;
const withGroupWrite = perms | 0o020;  // 0o775

Maskowanie podsieci IP

Dla 192.168.1.10/24 adres sieci wyłuska się przez AND z maską:

const ip      = 0xC0A8010A;  // 192.168.1.10
const mask    = 0xFFFFFF00;  // 255.255.255.0 (/24)
const network = ip & mask;   // 0xC0A80100 = 192.168.1.0

Upakowane ID: Snowflake

Snowflake od Twittera upakowuje timestamp, identyfikator maszyny i sekwencję w 64-bitową liczbę całkowitą:

┌─ 1 bit ─┬─── 41 bitów ───┬─ 10 bitów ─┬─ 12 bitów ─┐
│  znak   │   timestamp    │  maszyna   │   seq      │
└─────────┴────────────────┴────────────┴────────────┘

Zakodowanie ID to dwa przesunięcia i dwa OR-y:

const id = (BigInt(timestamp) << 22n) |
           (BigInt(machineId) << 12n) |
            BigInt(sequence);

Dekodowanie jest odwrotne: przesunięcie w prawo i maska. Pełen przegląd, kiedy wybrać Snowflake, ULID czy UUIDv7, znajdziesz w naszym porównaniu rozproszonych ID.

Pułapki specyficzne dla języków

JavaScript: pułapka rzutowania na 32 bity

JavaScript przed każdą operacją bitową konwertuje operandy na 32-bitowe liczby całkowite ze znakiem, a następnie wynik z powrotem na Number. Każda wartość powyżej 2³¹ − 1 = 2147483647 się przepełnia:

2147483647 | 0   // 2147483647   (still fine)
2147483648 | 0   // -2147483648  (overflowed!)
4294967295 | 0   // -1           (all bits set, interpreted signed)

Do pracy z 64-bitami użyj BigInt. Ma niezależne operatory bitowe bez ograniczenia szerokości:

(2n ** 40n) | 1n  // 1099511627777n

Błędy priorytetu operatorów

To jeden z najczęstszych prawdziwych błędów bitowych:

// Buggy: reads as (x & (1 == 0)) because == binds tighter than &
if (x & 1 == 0) { /* ... */ }

// Correct: parenthesize
if ((x & 1) == 0) { /* ... */ }

Operatory porównania wiążą silniej niż bitowe AND/OR/XOR w C, JavaScripcie, Pythonie, Go i większości potomków. Gdy masz wątpliwości — postaw nawiasy.

Tabela porównawcza języków

JęzykRzutowanie szerokościUjemne >>Wsparcie BigInt
JavaScriptwymusza 32-bit ze znakiem; >>> bez znakuarytmetyczneBigInt ma osobne operatory
Pythondowolna precyzja; brak stałej szerokościarytmetycznenatywne
Gościsłe; wartość przesunięcia musi być bez znakuarytmetyczne dla typów ze znakiemmath/big
C/C++zależne od typu; int, unsigned itd.dla typów ze znakiem zależne od implementacjibrak wbudowanego
Rustścisłe; w trybie debug panika przy przepełnieniuarytmetyczne dla typów ze znakiemu128 / zewnętrzne crate’y

Pythonowy zwrot z nieskończoną szerokością

Liczby całkowite w Pythonie nie mają stałej szerokości, więc logika U2 rozszerza się „w nieskończoność” w lewo. Dlatego ~5 to -6 (a nie 250 ani 65530): Python traktuje wynik jako liczbę całkowitą ujemną, a nie jako układ bitów o stałej szerokości. Gdy potrzebujesz semantyki zawijania, zamaskuj jawnie:

# Simulate 8-bit NOT
(~5) & 0xFF  # 250

Wydajność — sprawdzenie z rzeczywistością w 2026 roku

Powszechny mit głosi, że operacje bitowe są „zawsze szybsze”. W 2026 roku to półprawda.

Kompilatory same wykonują oczywiste przepisania. Nowoczesne optymalizatory automatycznie zamieniają x * 2 na x << 1. Pisanie x << 1 w kodzie aplikacyjnym dla wydajności to kult cargo. Nie pomaga, a szkodzi czytelności.

Tam, gdzie kod bitowy naprawdę wygrywa:

  • gorące pętle w kodzie numerycznym: popcount, liczenie wiodących i końcowych zer, silniki szachowe oparte na bitboardach;
  • zwarte struktury danych: filtry Blooma, roaring bitmaps, drzewa Fenwicka;
  • rejestry sprzętowe i I/O odwzorowane w pamięci: kod systemów wbudowanych, jądra, firmware;
  • prymitywy kryptograficzne: AES, ChaCha20 i SHA są zbudowane z XOR-ów, rotacji i przesunięć;
  • kompresja i dekompresja: kodowanie Huffmana, RLE, upakowane liczby całkowite;
  • silniki bazodanowe: indeksy bitmapowe, upakowane formaty kolumnowe, np. kodowanie słownikowe Parquet.

Tam, gdzie nie pomaga: zastępowanie x % 2 przez x & 1 w funkcji logiki biznesowej uruchamianej dwa razy na żądanie. Przyspieszenie jest niemierzalne, koszt czytelności realny.

Jednym przypadkiem, w którym manipulacja bitami zawsze wygrywa, jest zużycie pamięci. Upakowanie 32 flag w int oszczędza 31 bajtów względem 32 wartości logicznych. W skali (miliony rekordów użytkowników, miliardy zdarzeń) to różnica między układem przyjaznym dla cache’u a obciążeniem młócącym L2.

Szybka ściąga

OperacjaOperatorPrzykładWynikTypowe zastosowanie
AND&0b1100 & 0b10100b1000maskowanie / wyłuskiwanie bitów
OR|0b1100 | 0b10100b1110łączenie flag
XOR^0b1100 ^ 0b10100b0110przełączanie / wykrywanie różnic
NOT~~0b1100...11110011inwersja na potrzeby maski
Przesunięcie w lewo<<1 << 38mnożenie przez 2ⁿ
Przesunięcie w prawo>>16 >> 24dzielenie przez 2ⁿ (ze znakiem)
Przesunięcie w prawo bez znaku (JS)>>>-1 >>> 04294967295traktowanie jako bez znaku
Ustaw bit n|x | (1 << n)włączenie bitu
Wyzeruj bit n& ~x & ~(1 << n)wyłączenie bitu
Przełącz bit n^x ^ (1 << n)odwrócenie bitu
Sprawdź bit n&(x >> n) & 10 lub 1test bitu
Najniższy ustawiony bit& -x & -xwyizolowanie bitu
Czy potęga dwójki&x > 0 && (x & (x-1)) == 0booltest potęgi

FAQ

Czym różni się logiczne (&&) i bitowe (&) AND?

Logiczne AND działa na całych wartościach logicznych i krótko spina obliczenia, więc false && expr nigdy nie wartościuje expr. Bitowe AND działa na poszczególnych bitach liczb całkowitych i zawsze wartościuje obie strony. Używaj && do warunków, & do manipulacji bitami.

Dlaczego ~1 daje -2 w większości języków?

Bitowe NOT na 1 odwraca każdy bit, dając uzupełnienie do jedności. W reprezentacji U2 odwrócenie wszystkich bitów x daje -(x + 1), więc ~1 to -2, ~0 to -1, a ~(-1) to 0. Ta tożsamość obowiązuje w JavaScripcie, Pythonie, Go, C, Ruście oraz w każdym innym języku, który przechowuje liczby całkowite ze znakiem w U2.

Czy x << 1 jest naprawdę szybsze niż x * 2?

Nie w praktyce. Każdy nowoczesny kompilator rozpoznaje x * 2 i emituje na poziomie maszyny tę samą instrukcję przesunięcia, więc benchmarki nie pokazują mierzalnej różnicy na x86 ani ARM. Stosuj x * 2 dla czytelności; << zarezerwuj na sytuacje, w których celowo myślisz w bitach — np. budujesz maskę bitową albo upakowujesz strukturalne ID.

Czy JavaScript wspiera 64-bitowe operacje bitowe?

JavaScript nie wspiera 64-bitowych operacji bitowych standardowymi operatorami &, |, ^, <<, >>, ponieważ wymuszają one rzutowanie operandów na 32-bitowe liczby całkowite ze znakiem przed wykonaniem operacji. Dla wartości 64-bitowych lub większych użyj literałów BigInt w stylu 1n << 40n, które dają operacje bitowe o dowolnej precyzji z własnymi pasującymi operatorami.

Jak efektywnie policzyć liczbę ustawionych bitów?

Skorzystaj z wbudowanej funkcji języka: bits.OnesCount w Go, Integer.bitCount w Javie, .bit_count() w Pythonie 3.10+, intrinsiki popcount w C/C++. Mapują się na pojedynczą instrukcję CPU POPCNT na nowoczesnych x86 i ARM.

Kiedy stosować maski bitowe zamiast struktury wartości logicznych?

Maski bitowe wybierz, gdy musisz przechowywać wiele wartości logicznych zwarcie (bazy danych, protokoły sieciowe, formaty plików) lub szybko testować kombinacje pojedynczym AND, np. flags & REQUIRED_MASK. Strukturę wartości logicznych zostaw, gdy pola mają różne typy, gdy potrzebujesz opisowego wyjścia debugowania albo gdy czytelność liczy się bardziej niż kilka bajtów pamięci.

Co się dzieje przy przesunięciu o więcej niż szerokość bitową?

W C/C++ — niezdefiniowane. W JavaScripcie wartość przesunięcia jest brana mod 32, więc 1 << 32 to 1, a nie 0. W Pythonie nie ma szerokości, więc 1 << 100 to po prostu większa liczba całkowita. Nigdy nie polegaj na zachowaniu przy nadmiernym przesunięciu; w razie potrzeby sam zamaskuj wartość przesunięcia.

Dlaczego pythonowe ~5 daje -6 zamiast 2?

Liczby całkowite w Pythonie nie mają stałej szerokości, więc U2 rozszerza się koncepcyjnie w nieskończoność. ~5 równa się -(5 + 1) = -6, tak samo jak w każdym innym języku z U2. Jeśli chcesz „odwróconej” 8-bitowej wartości 250, zamaskuj: (~5) & 0xFF.

Czy szyfrowanie XOR jest bezpieczne?

One-time pad z prawdziwie losowym kluczem o długości równej wiadomości jest informacyjnie nieprzełamywalny. Powtórne użycie tego samego klucza między wiadomościami jest katastrofalnie niebezpieczne, a standardowe „szyfrowanie” XOR krótkim, powtarzającym się kluczem łamie się trywialnie. Prawdziwe szyfry takie jak AES i ChaCha20 używają XOR wewnętrznie, ale jako jednego z wielu kroków.

Jak ręcznie zapisać liczbę ujemną w U2?

Zapisz wartość dodatnią w systemie dwójkowym o docelowej szerokości, odwróć każdy bit, a potem dodaj 1. Przykład: -5 w 8 bitach = 00000101 → odwróć na 11111010 → dodaj 1 → 11111011. Sprawdź w naszym konwerterze systemów liczbowych, konwertując 251 (interpretacja 11111011 bez znaku) i potwierdzając, że dostajesz 11111011.

Powiązane narzędzia i dalsza lektura

Powiązane artykuły

Zobacz wszystkie artykuły