Системы счисления: двоичная, шестнадцатеричная, десятичная и битовые операции
Полное руководство по системам счисления, включая двоичную, шестнадцатеричную, десятичную, преобразование между ними и битовые операции с практическими примерами.
Суть вопроса
Компьютеры используют двоичную систему (0 и 1). Шестнадцатеричная система служит компактным представлением двоичных значений. Битовые операции позволяют напрямую манипулировать данными на уровне битов.
Путь обучения
Начинающие (шаги 1-3):
- Разберитесь с основами систем счисления (десятичная, двоичная, шестнадцатеричная)
- Потренируйтесь в простых преобразованиях (десятичная ↔ двоичная ↔ шестнадцатеричная)
- Изучите базовые битовые операции (AND, OR, XOR)
Продвинутый уровень (шаги 4-6): 4. Поймите дополнительный код и представление отрицательных чисел 5. Практические применения (IP-адреса, цвета, MAC-адреса) 6. Операции сдвига и манипуляция битами
Эксперты (шаги 7-10): 7. Продвинутые темы (BCD, код Грея, CRC) 8. Формат чисел с плавающей запятой IEEE 754 9. Порядок байтов и сетевой порядок байтов 10. Оптимизация производительности с помощью битовых операций
💡 Совет: Начните с интерактивных упражнений, чтобы проверить своё понимание!
Определение ключевых понятий
Системы счисления — это методы представления чисел с использованием различных оснований. Компьютеры изнутри используют двоичную систему (основание 2), тогда как люди предпочитают десятичную систему (основание 10).
Основные системы счисления:
Десятичная система (основание 10)
- Цифры: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
- Позиционные значения: 10⁰, 10¹, 10², 10³, …
- Применение: Общение между людьми, повседневная математика
- Пример: 123 = 1×10² + 2×10¹ + 3×10⁰
Визуальное представление:
1 2 3
↓ ↓ ↓
10² 10¹ 10⁰
100 10 1
= 100 + 20 + 3 = 123
Двоичная система (основание 2)
- Цифры: 0, 1
- Позиционные значения: 2⁰, 2¹, 2², 2³, …
- Применение: Внутреннее представление в компьютере
- Пример: 1011 = 1×2³ + 0×2² + 1×2¹ + 1×2⁰ = 11
⚠️ Важно: Компьютеры работают только с 0 и 1. Все данные в конечном итоге хранятся как двоичные числа!
Визуальное представление:
1 0 1 1
↓ ↓ ↓ ↓
2³ 2² 2¹ 2⁰
8 4 2 1
= 8 + 0 + 2 + 1 = 11
Шестнадцатеричная система (основание 16)
- Цифры: 0-9, A, B, C, D, E, F
- Позиционные значения: 16⁰, 16¹, 16², 16³, …
- Применение: Компактное представление двоичных значений, цвета, адреса памяти
- Пример: A3 = 10×16¹ + 3×16⁰ = 163
💡 Совет: 1 шестнадцатеричная цифра = 4 двоичные цифры. Шестнадцатеричная система идеальна для представления двоичных данных, так как она компактнее и понятнее!
Визуальное представление:
A 3
↓ ↓
16¹ 16⁰
16 1
= 160 + 3 = 163
Восьмеричная система (основание 8)
- Цифры: 0, 1, 2, 3, 4, 5, 6, 7
- Позиционные значения: 8⁰, 8¹, 8², 8³, …
- Применение: Исторически используется в Unix-системах
- Пример: 75 = 7×8¹ + 5×8⁰ = 61
📜 История: Восьмеричная система часто применялась в ранних Unix-системах (например, права доступа в
chmod 755). Сегодня шестнадцатеричная система распространена больше.
Визуальное представление:
7 5
↓ ↓
8¹ 8⁰
8 1
= 56 + 5 = 61
Ключевые пункты для подготовки
- Десятичная система: основание 10, цифры 0-9, позиционные значения 10ⁿ
- Двоичная система: основание 2, цифры 0-1, представление в компьютере
- Шестнадцатеричная система: основание 16, цифры 0-9, A-F, компактное представление
- Преобразование: деление/умножение на основание, метод позиционных значений
- Битовые операции: AND, OR, XOR, NOT, операции сдвига
- Дополнительный код: отрицательные числа в двоичной системе
- Релевантно для экзаменов: основа компьютерной архитектуры и программирования
Основные компоненты
- Системы счисления: десятичная, двоичная, шестнадцатеричная, восьмеричная
- Преобразование: между различными основаниями
- Битовые операции: AND, OR, XOR, NOT, сдвиг
- Дополнительный код: отрицательные числа
- Компьютерная арифметика: сложение, вычитание, умножение
- Типы данных: биты, байты, слова
- Представление памяти: шестнадцатеричные адреса
- Обнаружение ошибок: чётность, контрольные суммы
Пошаговые примеры преобразований
💡 Совет: Регулярно отрабатывайте эти преобразования, они являются основой для понимания компьютерных систем! Кроме того, они встречаются почти во всех экзаменационных заданиях.
Наш бесплатный онлайн и офлайн калькулятор:
Zahlensystem-Umrechnung
Десятичная в двоичную (деление на 2)
Пример: 13₁₀ → двоичная
13 ÷ 2 = 6 остаток 1 ← младший бит
6 ÷ 2 = 3 остаток 0
3 ÷ 2 = 1 остаток 1
1 ÷ 2 = 0 остаток 1 ← старший бит
Читаем снизу вверх: 1101₂
Двоичная в десятичную (метод позиционных значений)
Пример: 1101₂ → десятичная
1 1 0 1
↓ ↓ ↓ ↓
2³ 2² 2¹ 2⁰
8 4 2 1
= 1×8 + 1×4 + 0×2 + 1×1
= 8 + 4 + 0 + 1
= 13₁₀
Десятичная в шестнадцатеричную (деление на 16)
Пример: 255₁₀ → шестнадцатеричная
255 ÷ 16 = 15 остаток 15 (F)
15 ÷ 16 = 0 остаток 15 (F)
Читаем снизу вверх: FF₁₆
Шестнадцатеричная в двоичную (4-битные группы)
Пример: A3₁₆ → двоичная
A (10) 3
↓ ↓
1010 0011
Итого: 10100011₂
Двоичная в шестнадцатеричную (4-битные группы)
Пример: 10100011₂ → шестнадцатеричная
1010 0011
↓ ↓
A 3
Итого: A3₁₆
Примеры из практики
1. Преобразование между системами счисления
public class ZahlensystemUmrechnung {
// Dezimal zu Binär
public static String dezimalZuBinaer(int dezimal) {
if (dezimal == 0) return "0";
StringBuilder binaer = new StringBuilder();
while (dezimal > 0) {
binaer.append(dezimal % 2);
dezimal /= 2;
}
return binaer.reverse().toString();
}
// Binär zu Dezimal
public static int binaerZuDezimal(String binaer) {
int dezimal = 0;
int potenz = 0;
for (int i = binaer.length() - 1; i >= 0; i--) {
if (binaer.charAt(i) == '1') {
dezimal += Math.pow(2, potenz);
}
potenz++;
}
return dezimal;
}
// Dezimal zu Hexadezimal
public static String dezimalZuHex(int dezimal) {
if (dezimal == 0) return "0";
char[] hexZiffern = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
StringBuilder hex = new StringBuilder();
while (dezimal > 0) {
int rest = dezimal % 16;
hex.append(hexZiffern[rest]);
dezimal /= 16;
}
return hex.reverse().toString();
}
// Hexadezimal zu Dezimal
public static int hexZuDezimal(String hex) {
int dezimal = 0;
String hexZiffern = "0123456789ABCDEF";
for (int i = 0; i < hex.length(); i++) {
char ziffer = hex.charAt(i);
int wert = hexZiffern.indexOf(ziffer);
dezimal = dezimal * 16 + wert;
}
return dezimal;
}
// Binär zu Hexadezimal
public static String binaerZuHex(String binaer) {
// Binär in 4er-Gruppen aufteilen
while (binaer.length() % 4 != 0) {
binaer = "0" + binaer;
}
StringBuilder hex = new StringBuilder();
for (int i = 0; i < binaer.length(); i += 4) {
String nibble = binaer.substring(i, i + 4);
int wert = binaerZuDezimal(nibble);
hex.append(dezimalZuHex(wert));
}
return hex.toString();
}
// Hexadezimal zu Binär
public static String hexZuBinaer(String hex) {
String[] binaerMap = {
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"
};
StringBuilder binaer = new StringBuilder();
for (int i = 0; i < hex.length(); i++) {
char ziffer = hex.charAt(i);
int wert = "0123456789ABCDEF".indexOf(ziffer);
binaer.append(binaerMap[wert]);
}
// Führende Nullen entfernen
while (binaer.length() > 1 && binaer.charAt(0) == '0') {
binaer.deleteCharAt(0);
}
return binaer.toString();
}
public static void main(String[] args) {
int zahl = 175;
System.out.println("Zahl: " + zahl);
System.out.println("Binär: " + dezimalZuBinaer(zahl));
System.out.println("Hex: " + dezimalZuHex(zahl));
String binaer = "10101111";
String hex = "AF";
System.out.println("\nBinär " + binaer + " = Dezimal " + binaerZuDezimal(binaer));
System.out.println("Hex " + hex + " = Dezimal " + hexZuDezimal(hex));
System.out.println("Binär " + binaer + " = Hex " + binaerZuHex(binaer));
System.out.println("Hex " + hex + " = Binär " + hexZuBinaer(hex));
}
}
2. Побитовые операции в разных языках
// Java побитовые операции
public class BitOperationen {
public static void main(String[] args) {
int a = 12; // 1100 в двоичной
int b = 10; // 1010 в двоичной
System.out.println("a = " + a + " (двоичная: " + Integer.toBinaryString(a) + ")");
System.out.println("b = " + b + " (двоичная: " + Integer.toBinaryString(b) + ")");
// Побитовое И (&)
int and = a & b; // 1100 & 1010 = 1000 (8)
System.out.println("a & b = " + and + " (двоичная: " + Integer.toBinaryString(and) + ")");
// Побитовое ИЛИ (|)
int or = a | b; // 1100 | 1010 = 1110 (14)
System.out.println("a | b = " + or + " (двоичная: " + Integer.toBinaryString(or) + ")");
// Побитовое исключающее ИЛИ (^)
int xor = a ^ b; // 1100 ^ 1010 = 0110 (6)
System.out.println("a ^ b = " + xor + " (двоичная: " + Integer.toBinaryString(xor) + ")");
// Побитовое НЕ (~)
int notA = ~a; // ~1100 = 0011 (с дополнением до двух)
System.out.println("~a = " + notA + " (двоичная: " + Integer.toBinaryString(notA) + ")");
// Левый сдвиг (<<)
int leftShift = a << 2; // 1100 << 2 = 110000 (48)
System.out.println("a << 2 = " + leftShift + " (двоичная: " + Integer.toBinaryString(leftShift) + ")");
// Правый сдвиг (>>)
int rightShift = a >> 1; // 1100 >> 1 = 0110 (6)
System.out.println("a >> 1 = " + rightShift + " (двоичная: " + Integer.toBinaryString(rightShift) + ")");
// Беззнаковый правый сдвиг (>>>)
int unsignedRightShift = a >>> 1; // 1100 >>> 1 = 0110 (6)
System.out.println("a >>> 1 = " + unsignedRightShift + " (двоичная: " + Integer.toBinaryString(unsignedRightShift) + ")");
// Практическое применение
praktischeAnwendungen();
}
private static void praktischeAnwendungen() {
System.out.println("\n=== Практическое применение ===");
// Проверить бит (установлен ли 3-й бит?)
int zahl = 12; // 1100
int bitPosition = 2;
boolean bitSet = (zahl & (1 << bitPosition)) != 0;
System.out.println("Бит " + bitPosition + " в " + zahl + " установлен: " + bitSet);
// Установить бит
int mitBit = zahl | (1 << bitPosition);
System.out.println("Установить бит " + bitPosition + ": " + mitBit);
// Очистить бит
int ohneBit = zahl & ~(1 << bitPosition);
System.out.println("Очистить бит " + bitPosition + ": " + ohneBit);
// Переключить бит
int umgeschaltet = zahl ^ (1 << bitPosition);
System.out.println("Переключить бит " + bitPosition + ": " + umgeschaltet);
// Извлечь цвет из RGB-значений
int farbe = 0xFF6B35; // Оранжевый
int rot = (farbe >> 16) & 0xFF;
int gruen = (farbe >> 8) & 0xFF;
int blau = farbe & 0xFF;
System.out.println("\nЦвет: #" + Integer.toHexString(farbe).toUpperCase());
System.out.println("Красный: " + rot);
System.out.println("Зелёный: " + gruen);
System.out.println("Синий: " + blau);
}
}
3. Дополнение до двух для отрицательных чисел
⚠️ Важно: дополнение до двух это стандарт представления отрицательных чисел в современных компьютерах. Избегайте дополнения до единицы и прямого кода с знаком.
public class Zweierkomplement {
// Вычислить дополнение до двух
public static String zweierkomplement(int zahl, int bits) {
if (zahl >= 0) {
return String.format("%" + bits + "s", Integer.toBinaryString(zahl)).replace(' ', '0');
}
// Отрицательное число: 2^bits - |zahl|
int positiv = (int) (Math.pow(2, bits) + zahl);
return String.format("%" + bits + "s", Integer.toBinaryString(positiv)).replace(' ', '0');
}
// Преобразовать из дополнения до двух в десятичное число
public static int vonZweierkomplement(String binaer) {
int bits = binaer.length();
// Если старший бит равен 0, число положительное
if (binaer.charAt(0) == '0') {
return Integer.parseInt(binaer, 2);
}
// Отрицательное число: - (2^bits - значение)
int wert = Integer.parseInt(binaer, 2);
return wert - (int) Math.pow(2, bits);
}
public static void main(String[] args) {
int[] zahlen = {13, 5, 0, -1, -5, -13};
int bits = 8;
System.out.println("Дополнение до двух с " + bits + " битами:");
System.out.println("Число\tДвоичная\tДесятичная");
System.out.println("-----\t--------\t----------");
for (int zahl : zahlen) {
String binaer = zweierkomplement(zahl, bits);
System.out.println(zahl + "\t" + binaer + "\t" + vonZweierkomplement(binaer));
}
// Показать диапазон
System.out.println("\nДиапазон при " + bits + " битах:");
System.out.println("Минимум: " + (-(int) Math.pow(2, bits-1)));
System.out.println("Максимум: " + ((int) Math.pow(2, bits-1) - 1));
// Демонстрация переполнения
System.out.println("\nДемонстрация переполнения:");
int max = (int) Math.pow(2, bits-1) - 1;
int ueberlauf = max + 1;
System.out.println("Макс: " + max + " -> " + zweierkomplement(max, bits));
System.out.println("Макс+1: " + ueberlauf + " -> " + zweierkomplement(ueberlauf, bits));
System.out.println("Ожидается: " + (-(int) Math.pow(2, bits-1)) + " -> " + zweierkomplement(-(int) Math.pow(2, bits-1), bits));
}
}
4. Компьютерная арифметика
⚠️ Внимание: двоичная арифметика может привести к переполнению. Всегда проверяйте границы диапазона ваших типов данных.
public class Computerarithmetik {
// Двоичное сложение
public static String binaerAddition(String a, String b) {
int laenge = Math.max(a.length(), b.length());
// Дополнить нулями в начале
a = String.format("%" + laenge + "s", a).replace(' ', '0');
b = String.format("%" + laenge + "s", b).replace(' ', '0');
StringBuilder ergebnis = new StringBuilder();
int carry = 0;
// Складывать справа налево
for (int i = laenge - 1; i >= 0; i--) {
int summe = carry + (a.charAt(i) - '0') + (b.charAt(i) - '0');
ergebnis.append(summe % 2);
carry = summe / 2;
}
// Добавить перенос в конце
if (carry > 0) {
ergebnis.append(carry);
}
return ergebnis.reverse().toString();
}
// Двоичное вычитание (метод дополнения до двух)
public static String binaerSubtraktion(String a, String b) {
// Инвертировать b (дополнение до двух)
String negiert = zweierkomplementNegieren(b);
// a + (-b)
return binaerAddition(a, negiert);
}
private static String zweierkomplementNegieren(String binaer) {
// Инвертировать биты
StringBuilder invertiert = new StringBuilder();
for (char bit : binaer.toCharArray()) {
invertiert.append(bit == '0' ? '1' : '0');
}
// Добавить 1
return binaerAddition(invertiert.toString(), "1");
}
// Двоичное умножение
public static String binaerMultiplikation(String a, String b) {
int aDez = Integer.parseInt(a, 2);
int bDez = Integer.parseInt(b, 2);
int produkt = aDez * bDez;
return Integer.toBinaryString(produkt);
}
// Арифметика с фиксированной точкой
public static double festePunktAddition(double a, double b, int nachkommastellen) {
int faktor = (int) Math.pow(10, nachkommastellen);
int aInt = (int) Math.round(a * faktor);
int bInt = (int) Math.round(b * faktor);
int ergebnisInt = aInt + bInt;
return (double) ergebnisInt / faktor;
}
// Представление чисел с плавающей точкой (упрощённо)
public static void gleitkommaDarstellung(double zahl) {
if (zahl == 0) {
System.out.println("0 = 0.0 × 2^0");
return;
}
boolean negativ = zahl < 0;
zahl = Math.abs(zahl);
int exponent = 0;
// Нормализовать
while (zahl >= 2.0) {
zahl /= 2.0;
exponent++;
}
while (zahl < 1.0) {
zahl *= 2.0;
exponent--;
}
System.out.println((negativ ? "-" : "") + zahl + " × 2^" + exponent);
}
public static void main(String[] args) {
System.out.println("=== Двоичная арифметика ===");
String a = "1011"; // 11
String b = "1101"; // 13
System.out.println("a = " + a + " (" + Integer.parseInt(a, 2) + ")");
System.out.println("b = " + b + " (" + Integer.parseInt(b, 2) + ")");
String summe = binaerAddition(a, b);
System.out.println("a + b = " + summe + " (" + Integer.parseInt(summe, 2) + ")");
String differenz = binaerSubtraktion(b, a);
System.out.println("b - a = " + differenz + " (" + Integer.parseInt(differenz, 2) + ")");
String produkt = binaerMultiplikation(a, b);
System.out.println("a × b = " + produkt + " (" + Integer.parseInt(produkt, 2) + ")");
System.out.println("\n=== Арифметика с фиксированной точкой ===");
double x = 12.34;
double y = 5.67;
double summeFP = festePunktAddition(x, y, 2);
System.out.println(x + " + " + y + " = " + summeFP + " (2 знака после запятой)");
System.out.println("\n=== Представление чисел с плавающей точкой ===");
double[] zahlen = {12.5, 0.75, -3.125, 256.0};
for (double zahl : zahlen) {
System.out.print(zahl + " = ");
gleitkommaDarstellung(zahl);
}
}
}
5. Битовые операции и системы счисления в Python
# Python системы счисления и битовые операции
def dezimal_zu_binaer(dezimal):
"""Dezimal zu Binär umrechnen"""
if dezimal == 0:
return "0"
binaer = ""
while dezimal > 0:
binaer = str(dezimal % 2) + binaer
dezimal //= 2
return binaer
def binaer_zu_dezimal(binaer):
"""Binär zu Dezimal umrechnen"""
return int(binaer, 2)
def dezimal_zu_hex(dezimal):
"""Dezimal zu Hexadezimal umrechnen"""
hex_ziffern = "0123456789ABCDEF"
if dezimal == 0:
return "0"
hex = ""
while dezimal > 0:
hex = hex_ziffern[dezimal % 16] + hex
dezimal //= 16
return hex
def hex_zu_dezimal(hex):
"""Hexadezimal zu Dezimal umrechnen"""
return int(hex, 16)
def bit_operationen_demo():
"""Bit-Operationen demonstrieren"""
a = 12 # 1100
b = 10 # 1010
print(f"a = {a} (Binär: {bin(a)})")
print(f"b = {b} (Binär: {bin(b)})")
# Bitweises AND
and_result = a & b
print(f"a & b = {and_result} (Binär: {bin(and_result)})")
# Bitweises OR
or_result = a | b
print(f"a | b = {or_result} (Binär: {bin(or_result)})")
# Bitweises XOR
xor_result = a ^ b
print(f"a ^ b = {xor_result} (Binär: {bin(xor_result)})")
# Bitweises NOT
not_a = ~a
print(f"~a = {not_a} (Binär: {bin(not_a & 0xFFFFFFFF)})")
# Left Shift
left_shift = a << 2
print(f"a << 2 = {left_shift} (Binär: {bin(left_shift)})")
# Right Shift
right_shift = a >> 1
print(f"a >> 1 = {right_shift} (Binär: {bin(right_shift)})")
def farbe_aus_rgb(rot, gruen, blau):
"""RGB-Farbe als 24-Bit-Wert zusammenfassen"""
return (rot << 16) | (gruen << 8) | blau
def rgb_aus_farbe(farbe):
"""RGB-Komponenten aus 24-Bit-Farbe extrahieren"""
rot = (farbe >> 16) & 0xFF
gruen = (farbe >> 8) & 0xFF
blau = farbe & 0xFF
return rot, gruen, blau
def bit_manipulation_demo():
"""Bit-Manipulation demonstrieren"""
zahl = 0b10101000 # 168
print(f"Ursprüngliche Zahl: {zahl} (Binär: {bin(zahl)})")
# Bit prüfen
bit_position = 3
bit_gesetzt = (zahl & (1 << bit_position)) != 0
print(f"Bit {bit_position} gesetzt: {bit_gesetzt}")
# Bit setzen
mit_bit = zahl | (1 << bit_position)
print(f"Setze Bit {bit_position}: {mit_bit} (Binär: {bin(mit_bit)})")
# Bit löschen
ohne_bit = zahl & ~(1 << bit_position)
print(f"Lösche Bit {bit_position}: {ohne_bit} (Binär: {bin(ohne_bit)})")
# Bit umschalten
umgeschaltet = zahl ^ (1 << bit_position)
print(f"Umschalte Bit {bit_position}: {umgeschaltet} (Binär: {bin(umgeschaltet)})")
def hauptprogramm():
"""Hauptprogramm mit allen Demonstrationen"""
print("=== Zahlensysteme Umrechnung ===")
zahl = 175
print(f"Dezimal {zahl}:")
print(f" Binär: {dezimal_zu_binaer(zahl)}")
print(f" Hex: {dezimal_zu_hex(zahl)}")
print("\n=== Bit-Operationen ===")
bit_operationen_demo()
print("\n=== Bit-Manipulation ===")
bit_manipulation_demo()
print("\n=== Farben als RGB ===")
orange = farbe_aus_rgb(255, 107, 53)
print(f"Orange: #{orange:06X}")
r, g, b = rgb_aus_farbe(orange)
print(f"RGB: ({r}, {g}, {b})")
print("\n=== Zweierkomplement (8-Bit) ===")
for i in range(-5, 6):
if i >= 0:
binaer = format(i, '08b')
else:
binaer = format((256 + i), '08b')
print(f"{i:3d}: {binaer}")
if __name__ == "__main__":
hauptprogramm()
Практические примеры
1. IP-адреса (IPv4)
IPv4-адреса состоят из 4 байтов (32 бита), обычно записываются в десятичной нотации:
Пример: 192.168.1.1
192 168 1 1
↓ ↓ ↓ ↓
11000000 10101000 00000001 00000001
C0 A8 01 01 (Hex)
Binär: 11000000101010000000000100000001
Hex: C0A80101
Маска подсети, пример: 255.255.255.0
255 255 255 0
↓ ↓ ↓ ↓
11111111 11111111 11111111 00000000
FF FF FF 00 (Hex)
2. MAC-адреса
MAC-адреса содержат 6 байтов (48 битов), обычно записываются в шестнадцатеричной нотации:
Пример: 00:1A:2B:3C:4D:5E
00:1A:2B:3C:4D:5E
↓ ↓ ↓ ↓ ↓ ↓
00000000:00011010:00101011:00111100:01001101:01011110
OUI (производитель): 00:1A:2B
ID устройства: 3C:4D:5E
3. Unicode и UTF-8
Символы Unicode представлены кодовыми точками, UTF-8 кодирует их в байты:
Пример: ‘A’ (U+0041)
Unicode: U+0041
Dezimal: 65
Binär: 01000001
UTF-8: 01000001 (1 Byte)
Пример: ’€’ (U+20AC)
Unicode: U+20AC
Dezimal: 8364
Binär: 00100000 10101100
UTF-8: 11100010 10000011 10101100 (3 Bytes)
Hex: E2 82 AC
4. Цветовые коды (RGB)
Веб-цвета представлены 24-битными шестнадцатеричными значениями:
Пример: #FF6B35 (оранжевый)
#FF6B35
↓↓↓↓↓↓
Красный Зелёный Синий
FF 6B 35
↓ ↓ ↓
255 107 53
Binär: 11111111 01101011 00110101
Пример Java:
int orange = 0xFF6B35;
int rot = (orange >> 16) & 0xFF; // 255
int gruen = (orange >> 8) & 0xFF; // 107
int blau = orange & 0xFF; // 53
5. Размеры файлов (двоичные vs десятичные)
Двоичные префиксы (IEC 80000-13):
1 KiB = 2¹⁰ = 1,024 Bytes
1 MiB = 2²⁰ = 1,048,576 Bytes
1 GiB = 2³⁰ = 1,073,741,824 Bytes
Десятичные префиксы (SI):
1 KB = 10³ = 1,000 Bytes
1 MB = 10⁶ = 1,000,000 Bytes
1 GB = 10⁹ = 1,000,000,000 Bytes
Пример: жесткий диск 1 GB
Производитель (десятичная): 1,000,000,000 Bytes
Операционная система (двоичная): 1,000,000,000 ÷ 1,073,741,824 = 0.93 GB
6. ASCII-таблица (выборка)
| Символ | Dezimal | Hex | Binär |
|---|---|---|---|
| A | 65 | 41 | 01000001 |
| B | 66 | 42 | 01000010 |
| C | 67 | 43 | 01000011 |
| a | 97 | 61 | 01100001 |
| b | 98 | 62 | 01100010 |
| c | 99 | 63 | 01100011 |
| 0 | 48 | 30 | 00110000 |
| 9 | 57 | 39 | 00111001 |
Интерактивные упражнения
Задачи на преобразование
Задача 1: десятичное в двоичное Преобразуйте следующие десятичные числа в двоичные:
- 42
- 127
- 255
Показать решения
42₁₀ = 101010₂
127₁₀ = 1111111₂
255₁₀ = 11111111₂Задача 2: двоичное в десятичное Преобразуйте следующие двоичные числа в десятичные:
- 10101
- 11110000
- 10000000
Показать решения
10101₂ = 21₁₀
11110000₂ = 240₁₀
10000000₂ = 128₁₀Задача 3: десятичное в шестнадцатеричное Преобразуйте следующие десятичные числа в шестнадцатеричные:
- 100
- 255
- 4095
Показать решения
100₁₀ = 64₁₆
255₁₀ = FF₁₆
4095₁₀ = FFF₁₆Задача 4: шестнадцатеричное в двоичное Преобразуйте следующие шестнадцатеричные числа в двоичные:
- A5
- FF
- 1B
Показать решения
A5₁₆ = 10100101₂
FF₁₆ = 11111111₂
1B₁₆ = 00011011₂Викторина по битовым операциям
Вопрос 1: Чему равно 12 & 10?
Показать решение
12₁₀ = 1100₂
10₁₀ = 1010₂
1100 & 1010 = 1000₂ = 8₁₀Вопрос 2: Чему равно 12 | 10?
Показать решение
12₁₀ = 1100₂
10₁₀ = 1010₂
1100 | 1010 = 1110₂ = 14₁₀Вопрос 3: Чему равно 12 ^ 10?
Показать решение
12₁₀ = 1100₂
10₁₀ = 1010₂
1100 ^ 1010 = 0110₂ = 6₁₀Вопрос 4: Чему равно 8 << 2?
Показать решение
8₁₀ = 1000₂
1000 << 2 = 100000₂ = 32₁₀Вопрос 5: Чему равно 16 >> 2?
Показать решение
16₁₀ = 10000₂
10000 >> 2 = 100₂ = 4₁₀Задачи для самопроверки
Задача 6: Манипуляция битами Дано число 42 (101010₂). Установите 3-й бит (считая справа, с индексацией с 0).
Показать решение
42 = 101010₂
3-й бит справа = позиция бита 2
42 | (1 << 2) = 42 | 4 = 46₁₀ = 101110₂Задача 7: Дополнительный код Представьте -5 в 8-битном дополнительном коде.
Показать решение
5₁₀ = 00000101₂
Инвертировать: 11111010₂
+ 1: 11111011₂
-5₁₀ = 11111011₂ (8-битный дополнительный код)Задача 8: IP-адрес Преобразуйте IP-адрес 10.0.0.1 в шестнадцатеричный формат.
Показать решение
10.0.0.1
↓ ↓ ↓ ↓
0A 00 00 01
Hex: 0A000001Типичные ошибки и подводные камни
1. Ошибки на единицу при индексации битов
Проблема: битовые позиции часто путают (индексация с 0 или с 1)
// ❌ Неправильно: битовая позиция 3 это 4-й бит справа
int bitPosition = 3;
boolean bitSet = (zahl & (1 << bitPosition)) != 0; // Проверяет бит 3 (4-й бит)
// ✅ Правильно: ясная документация индексации
// Битовая позиция 0 = крайний правый бит (LSB)
// Битовая позиция 7 = крайний левый бит в 8-битном числе
int bitPosition = 2; // 3-й бит справа (индексация с 0)
boolean bitSet = (zahl & (1 << bitPosition)) != 0;
2. Обработка знака при сдвиге
Проблема: правый сдвиг по-разному работает с числами со знаком и без знака
// Java: арифметический сдвиг вправо (>>) заполняет знаковый бит
int x = -8; // 11111111111111111111111111111000
int result = x >> 2; // 11111111111111111111111111111110 (-2)
// Логический сдвиг вправо (>>>) заполняет нулями
int x = -8;
int result = x >>> 2; // 00111111111111111111111111111110 (1073741822)
3. Проблемы переполнения
Проблема: переполнение целых чисел часто остаётся без внимания
// ❌ Без проверки переполнения
int max = Integer.MAX_VALUE; // 2147483647
int overflow = max + 1; // -2147483648 (переполнение!)
// ✅ С проверкой переполнения
if (max == Integer.MAX_VALUE) {
throw new ArithmeticException("Integer overflow");
}
4. Различные обозначения шестнадцатеричных чисел
Проблема: разные языки и контексты используют разные конвенции записи
// Различные обозначения:
0xFF // Java/C префикс
0xFF // C# префикс
0xFF // JavaScript префикс
#FF // CSS/Web
FFh // Ассемблер
$FF // Pascal
5. Забывают о порядке байтов
Проблема: игнорируют endianness при работе с байтами
// Прямой порядок байтов (x86, ARM): младший байт в начале
int wert = 0x12345678;
// В памяти: 78 56 34 12
// Обратный порядок байтов (сеть, PowerPC): старший байт в начале
// В памяти: 12 34 56 78
// Конвертация:
int littleEndian = 0x12345678;
int bigEndian = Integer.reverseBytes(littleEndian); // 0x78563412
6. Неправильное указание системы счисления при parseInt
Проблема: не указывают основание или указывают неверно
// ❌ Неправильно: парсит как десятичное число
int wert = Integer.parseInt("1010"); // 1010 (десятичное)
// ✅ Правильно: указываем основание
int wert = Integer.parseInt("1010", 2); // 10 (десятичное)
int hexWert = Integer.parseInt("FF", 16); // 255 (десятичное)
7. Выход за пределы диапазона дополнительного кода
Проблема: число не вмещается в указанную битовую ширину
// 8-битный дополнительный код: от -128 до 127
int wert = 200; // ❌ Выходит за пределы!
// Проверка диапазона:
if (wert < -128 || wert > 127) {
throw new IllegalArgumentException("Значение выходит за пределы 8-битного диапазона");
}
8. Деление целого числа вместо вещественного
Проблема: целочисленное деление отбрасывает дробную часть
// ❌ Неправильно: целочисленное деление
int ergebnis = 5 / 2; // 2 (вместо 2.5)
// ✅ Правильно: деление вещественных чисел
double ergebnis = 5.0 / 2.0; // 2.5
9. Отрицание против побитового НЕ
Проблема: путают логическое отрицание и битовое инвертирование
// Логическое НЕ (!)
boolean a = true;
boolean b = !a; // false
// Побитовое НЕ (~)
int x = 5; // 0101
int y = ~x; // 1010 (в дополнительном коде: -6)
10. Ведущие нули в шестнадцатеричной записи
Проблема: ведущие нули влияют на значение в некоторых контекстах
// В Java: 0x0F = 15, 0xF = 15 (одинаково)
// Но при сравнении строк:
String a = "0F";
String b = "F";
// a.equals(b) = false!
Практические советы для разработчиков
1. Отладка с просмотром в двоичной и шестнадцатеричной системе
Используйте инструменты IDE:
// IntelliJ/Eclipse: двоичный просмотр в отладчике
// Переменная: 175
// Двоичный: 10101111
// Hex: AF
Логирование в разных системах счисления:
System.out.println("Десятичное: " + zahl);
System.out.println("Двоичное: " + Integer.toBinaryString(zahl));
System.out.println("Шестнадцатеричное: " + Integer.toHexString(zahl));
System.out.println("Восьмеричное: " + Integer.toOctalString(zahl));
2. Битовые флаги в API
Эффективные флаги состояния:
// Определяем константы флагов
public static final int READ = 1 << 0; // 0001
public static final int WRITE = 1 << 1; // 0010
public static final int EXECUTE = 1 << 2; // 0100
// Комбинируем флаги
int permissions = READ | WRITE; // 0011
// Проверяем флаги
boolean canRead = (permissions & READ) != 0;
boolean canWrite = (permissions & WRITE) != 0;
boolean canExecute = (permissions & EXECUTE) != 0;
3. Преимущества битовых операций в производительности
Умножение и деление через сдвиги:
// Быстрее чем * 2
int x = 5;
int verdoppelt = x << 1; // 10
// Быстрее чем / 2
int halbiert = x >> 1; // 2
// Модуль 2^n через AND
int modulo8 = x & 0x7; // x % 8
⚠️ Важно: современные компиляторы часто оптимизируют это автоматически. Используйте сдвиги только в критичных местах.
4. Манипуляция цветовыми значениями
Эффективная работа с RGB:
// Создание цвета
int farbe = (255 << 16) | (107 << 8) | 53; // #FF6B35
// Извлечение компонентов
int rot = (farbe >> 16) & 0xFF;
int gruen = (farbe >> 8) & 0xFF;
int blau = farbe & 0xFF;
// Манипуляция цветом
int neueFarbe = farbe & 0x00FFFFFF; // Очистить красный компонент
neueFarbe |= (200 << 16); // Установить новое значение красного
5. Порядок байтов в сети
Обеспечение портативности:
// Host to Network Short (16-бит)
short hostPort = 8080;
short networkPort = Short.reverseBytes(hostPort);
// Network to Host Long (32-бит)
int networkAddress = 0xC0A80101; // 192.168.1.1
int hostAddress = Integer.reverseBytes(networkAddress);
6. Битовые маски для конфигурации
Компактное хранение конфигурации:
public class Config {
private int flags = 0;
public static final int DEBUG = 1 << 0;
public static final int VERBOSE = 1 << 1;
public static final int LOGGING = 1 << 2;
public void setFlag(int flag) {
flags |= flag;
}
public void clearFlag(int flag) {
flags &= ~flag;
}
public boolean hasFlag(int flag) {
return (flags & flag) != 0;
}
}
7. Экономная структура данных
Биты для булевых значений:
// Вместо 8 булевых значений (8 байт):
// boolean[] flags = new boolean[8];
// Один int (4 байта) для 8 флагов:
int flags = 0;
flags |= (1 << 3); // Установить 3-й флаг
8. Хеш-функции с битовыми операциями
Простая хеш-функция:
public static int simpleHash(String s) {
int hash = 0;
for (int i = 0; i < s.length(); i++) {
hash = (hash << 5) - hash + s.charAt(i);
}
return hash;
}
9. Вычисление чётности
Бит чётности для обнаружения ошибок:
public static boolean calculateParity(int x) {
boolean parity = false;
while (x != 0) {
parity = !parity;
x = x & (x - 1); // Удаляет младший установленный бит
}
return parity;
}
10. Проверка степени двойки
Эффективная проверка на степень двойки:
public static boolean isPowerOfTwo(int x) {
return x > 0 && (x & (x - 1)) == 0;
}
// Примеры:
// isPowerOfTwo(1) = true (2⁰)
// isPowerOfTwo(2) = true (2¹)
// isPowerOfTwo(4) = true (2²)
// isPowerOfTwo(8) = true (2³)
// isPowerOfTwo(6) = false
Продвинутые темы
1. BCD (Binary Coded Decimal)
BCD кодирует каждую десятичную цифру в 4 бита:
Пример: 42 в BCD
4 2
↓ ↓
0100 0010
BCD: 01000010
Преимущества:
- Простое преобразование в десятичную и из десятичной
- Точная десятичная арифметика
Недостатки:
- Неэффективное использование памяти (6 из 16 значений не используются)
- Более сложная арифметика
Реализация на Java:
public class BCD {
public static int decimalToBCD(int decimal) {
int bcd = 0;
int shift = 0;
while (decimal > 0) {
int digit = decimal % 10;
bcd |= (digit << shift);
decimal /= 10;
shift += 4;
}
return bcd;
}
public static int bcdToDecimal(int bcd) {
int decimal = 0;
int multiplier = 1;
while (bcd > 0) {
int digit = bcd & 0xF;
decimal += digit * multiplier;
bcd >>= 4;
multiplier *= 10;
}
return decimal;
}
}
2. Gray-Code
Gray-Code это двоичная система счисления, где последовательные значения отличаются только одним битом:
Таблица Gray-Code (4 бита):
Десятичное | Двоичное | Gray-Code
-----------|----------|----------
0 | 0000 | 0000
1 | 0001 | 0001
2 | 0010 | 0011
3 | 0011 | 0010
4 | 0100 | 0110
5 | 0101 | 0111
6 | 0110 | 0101
7 | 0111 | 0100
Двоичный в Gray-Code:
public static int binaryToGray(int binary) {
return binary ^ (binary >> 1);
}
Gray-Code в двоичный:
public static int grayToBinary(int gray) {
int binary = gray;
while (gray > 0) {
gray >>= 1;
binary ^= gray;
}
return binary;
}
Применение: Роторные энкодеры, минимизация ошибок при переключении
3. CRC (Cyclic Redundancy Check)
CRC это метод обнаружения ошибок при передаче данных:
Простая реализация CRC-8:
public class CRC8 {
private static final int POLYNOMIAL = 0x07;
public static int calculate(byte[] data) {
int crc = 0x00;
for (byte b : data) {
crc ^= b;
for (int i = 0; i < 8; i++) {
if ((crc & 0x80) != 0) {
crc = (crc << 1) ^ POLYNOMIAL;
} else {
crc <<= 1;
}
}
}
return crc & 0xFF;
}
}
Использование:
- Сетевые протоколы (Ethernet, USB)
- Проверка целостности файлов
- Обнаружение ошибок в памяти
4. IEEE 754 Формат чисел с плавающей точкой
Стандарт для представления вещественных чисел:
32-битная одиночная точность:
Бит 31: Знак (S)
Биты 30-23: Экспонента (E, 8 бит)
Биты 22-0: Мантисса (M, 23 бита)
Значение = (-1)^S × 2^(E-127) × (1 + M)
Пример: 12.5 в IEEE 754
12.5 = 1100.1₂ = 1.1001₂ × 2³
S = 0 (положительное)
E = 127 + 3 = 130 = 10000010₂
M = 10010000000000000000000
IEEE 754: 01000001010010000000000000000000
Hex: 41480000
Реализация на Java:
public class IEEE754 {
public static String floatToBits(float value) {
int bits = Float.floatToIntBits(value);
return String.format("%32s", Integer.toBinaryString(bits))
.replace(' ', '0');
}
public static float bitsToFloat(String bits) {
int intValue = Integer.parseInt(bits, 2);
return Float.intBitsToFloat(intValue);
}
}
5. Порядок байтов (Endianness)
Big Endian: Старший байт первым (сетевой порядок байтов) Little Endian: Младший байт первым (x86, ARM)
Пример: 0x12345678
Big Endian: 12 34 56 78
Little Endian: 78 56 34 12
Преобразование на Java:
public class Endianness {
// Little Endian в Big Endian
public static int littleToBig(int value) {
return Integer.reverseBytes(value);
}
// Big Endian в Little Endian
public static int bigToLittle(int value) {
return Integer.reverseBytes(value);
}
// Проверка порядка байтов системы
public static boolean isLittleEndian() {
int test = 0x12345678;
byte[] bytes = new byte[] {
(byte) (test >> 24),
(byte) (test >> 16),
(byte) (test >> 8),
(byte) test
};
return bytes[0] == 0x78; // Little Endian
}
}
Важно при работе с:
- Сетевыми протоколами (TCP/IP использует Big Endian)
- Форматами файлов
- Кроссплатформенной разработкой
6. Бит чётности
Простой метод обнаружения ошибок:
Even Parity (чётная чётность):
Данные: 1011
Чётность: 0 (чтобы количество 1s было чётным: 10110 → 3 единицы = нечётное ❌)
Чётность: 1 (чтобы количество 1s было чётным: 10111 → 4 единицы = чётное ✅)
Реализация на Java:
public class Parity {
public static boolean calculateEvenParity(byte data) {
int count = Integer.bitCount(data & 0xFF);
return (count % 2) == 0;
}
public static byte setEvenParity(byte data) {
if (calculateEvenParity(data)) {
return (byte) (data & 0x7F); // Бит чётности = 0
} else {
return (byte) (data | 0x80); // Бит чётности = 1
}
}
}
7. Контрольные суммы
Простые контрольные суммы для проверки целостности данных:
Простая контрольная сумма:
public class Checksum {
public static int calculate(byte[] data) {
int sum = 0;
for (byte b : data) {
sum += (b & 0xFF);
}
return sum & 0xFFFF; // 16-битная контрольная сумма
}
public static boolean verify(byte[] data, int checksum) {
return calculate(data) == checksum;
}
}
8. Base64-кодирование
Кодирование двоичных данных в ASCII-символы:
Пример:
Двоичное: 01000001 01000010 01000011 (ABC)
Base64: QUJD
Реализация на Java:
import java.util.Base64;
public class Base64Example {
public static String encode(String input) {
return Base64.getEncoder().encodeToString(input.getBytes());
}
public static String decode(String encoded) {
byte[] decoded = Base64.getDecoder().decode(encoded);
return new String(decoded);
}
}
9. Ротация битов
Ротация без потери битов:
Левая ротация:
public static int rotateLeft(int value, int shift) {
return (value << shift) | (value >>> (32 - shift));
}
Правая ротация:
public static int rotateRight(int value, int shift) {
return (value >>> shift) | (value << (32 - shift));
}
Пример:
int x = 0b11000000; // 192
int rotated = rotateLeft(x, 2); // 0b00000011 (3)
10. Расстояние Хэмминга
Количество различающихся битов между двумя значениями:
public static int hammingDistance(int a, int b) {
int xor = a ^ b;
return Integer.bitCount(xor);
}
// Пример:
// hammingDistance(0b1010, 0b1100) = 2
// 1010 ^ 1100 = 0110 (2 единицы)
Применение: коды исправления ошибок, криптография
Таблица преобразований
| Десятичное | Двоичное | Шестнадцатеричное | Восьмеричное |
|---|---|---|---|
| 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 |
Обзор битовых операций
Bit-Operationen
| Оператор | Символ | Описание | Пример |
|----------|--------|-------------|----------|
| AND | & | Побитовое И | 5 & 3 = 1 |
| OR | \| | Побитовое ИЛИ | `5 \| 3 = 7` |
| XOR | ^ | Исключающее ИЛИ | `5 ^ 3 = 6` |
| NOT | ~ | Побитовое НЕ | `~5 = -6` |
| Left Shift | << | Сдвиг влево | `5 << 2 = 20` |
| Right Shift | >> | Сдвиг вправо | `5 >> 1 = 2` |
| Unsigned Right Shift | >>> | Беззнаковый сдвиг вправо | `5 >>> 1 = 2` |
Размеры памяти
| Единица | Байты | Биты | Диапазон (беззнаковый) |
|---|---|---|---|
| Byte | 1 | 8 | 0 - 255 |
| Word | 2 | 16 | 0 - 65,535 |
| DWord | 4 | 32 | 0 - 4,294,967,295 |
| QWord | 8 | 64 | 0 - 18,446,744,073,709,551,615 |
Диапазон прямого кода со знаком
| Биты | Минимум | Максимум |
|---|---|---|
| 8 | -128 | 127 |
| 16 | -32,768 | 32,767 |
| 32 | -2,147,483,648 | 2,147,483,647 |
| 64 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
Преимущества и недостатки
Преимущества двоичной системы
- Простота: только два состояния (0 и 1)
- Надежность: легко реализуется без ошибок
- Эффективность: оптимальна для электронных схем
- Универсальность: основа всех цифровых систем
Преимущества шестнадцатеричной системы
- Компактность: 4 двоичных цифры = 1 шестнадцатеричная цифра
- Читаемость: короче и понятнее, чем двоичная
- Стандартизация: широко распространена в программировании
- Практичность: идеальна для адресов и цветов
Недостатки
- Абстрактность: интуитивно непонятна для человека
- Преобразования: требуют арифметических вычислений в уме
- Ошибки: легко ошибиться при ручном преобразовании
Часто встречаемые экзаменационные вопросы
1. **Преобразуйте 175 (десятичное) в двоичное и шестнадцатеричное!**
175₁₀ = 10101111₂ = AF₁₆
2. **Каков результат 12 & 10 (побитовое И)?**
12₁₀ = 1100₂, 10₁₀ = 1010₂ → 1100 & 1010 = 1000₂ = 8₁₀
3. **Объясните прямой код со знаком!**
Метод представления отрицательных чисел в двоичной системе путем инверсии битов и добавления 1.
4. **Для чего используются шестнадцатеричные числа?**
Компактное представление двоичных значений, цветов, адресов памяти, кодов ошибок.
Основные источники
- https://de.wikipedia.org/wiki/Zahlensystem
- https://de.wikipedia.org/wiki/Zweierkomplement
- https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html



