bitlvl
RU

Код Грея, BCD и popcount

Введите число в десятичном, hex или двоичном виде. Вы получите его код Грея (и обратный перевод), упаковку в BCD, количество установленных битов и чётность, с использованными формулами.

Разрядность

Последовательность кода Грея

Результаты и сообщения этого инструмента выводятся на английском языке.

Код Грея

В обычной двоичной записи при счёте от 7 (0111) к 8 (1000) одновременно меняются четыре бита. Если эти биты считывает механический энкодер или они выбираются по тактовому сигналу в момент изменения, может появиться любая смесь старых и новых битов, а мгновенное 1111 (15) — это большая ошибка. Код Грея (отражённый двоичный код) упорядочивает числа так, что соседние значения различаются ровно одним битом. Его используют поворотные энкодеры, карты Карно, некоторые АЦП и схемы коррекции ошибок.

Перевод в каждую сторону занимает одну строку:

gray   = n ^ (n >> 1)
binary = g; while (g >>= 1) binary ^= g;   // XOR со всеми сдвигами вправо

BCD

Двоично-десятичный код хранит каждую десятичную цифру в отдельном 4-битном полубайте: 1234 превращается в 0001 0010 0011 0100, что как hex-число равно 0x1234. Он тратит немного места впустую (полубайты A–F никогда не используются), зато делает десятичный вывод и точную десятичную арифметику тривиальными, поэтому его используют часы, калькуляторы, финансовый COBOL и микросхема часов реального времени в каждом ПК. Чтение BCD-байта как обычного двоичного числа даёт бессмыслицу — это и есть типичная ошибка.

Popcount и чётность

Вес Хэмминга (popcount) — это количество единичных битов. На современных CPU это одна инструкция (POPCNT), и на нём основаны расстояние Хэмминга, мощность битовых множеств и некоторые трюки хеширования. Чётность — это popcount mod 2; бит чётности — простейший код обнаружения ошибок, который ловит любой одиночный инвертированный бит.

// Трюк Кернигана: каждый шаг сбрасывает младший установленный бит
int count = 0; while (n) { n &= n - 1; count++; }

Вопросы

Почему поворотные энкодеры используют код Грея?

Между двумя соседними положениями меняется только один контакт, поэтому показание, снятое посреди перехода, всегда равно одному из двух соседних значений и никогда — случайному. Двоичные энкодеры во время многобитного перехода могут показать что угодно.

Код Грея единственный?

Отражённый двоичный код — стандартный, но любое упорядочение, в котором соседи различаются одним битом, — это «какой-то» код Грея. Для особых применений существуют сбалансированные и n-ичные коды Грея.

Как перевести BCD в двоичное число в коде?

Берите каждый полубайт как цифру: value = value*10 + nibble, от старшего полубайта к младшему. Или для двузначных байтов: ((b >> 4) * 10) + (b & 0x0F). Многим микросхемам RTC нужно именно это.

Как быстрее всего посчитать биты?

Используйте встроенную функцию: __builtin_popcount (C), bits.OnesCount (Go), int.bit_count() (Python 3.10+), u32::count_ones (Rust). Там, где это возможно, они компилируются в одну инструкцию.