Как перевести число в биты
Перейти к содержимому

Как перевести число в биты

  • автор:

Как перевести число в биты

На аппаратном уровне вся информация в компьютере представляет последовательность электрических сигналов. Например, в какой-то определенной ячейке памяти может быть иметься сильное напряжение, или оно может быть очень слабым. Для описания состояния сигнала информатике используется термина бит . По сути бит является наименьшей единицей информации в компьютере. Бит может иметь значение 1 (есть сигнал, что обычно соответствует напряжению от 2 до 5 V) или 0 (сигнал отсутствует или слабый — обычно от 0 до 2 V).

8 битов составляют байт . Фактически байт — это наименьшая единица информации, которую можно прочитать или записать в память большинством современных процессоров.

Один бит может принимать два значения: 0 и 1. Два бита вместе могут принимать четыре значения: 00, 01, 10 и 11. Три бита могут принимать восемь значений: 000, 001, 010, 011, 100, 101, 110 и 111. Обобщая, группа из n битов может принимать 2 n значений. Таким образом, группа из 8 бит или 1 байт может представлять 2 8 , то есть 256 уникальных значений. Таким образом, вся информация в компьютере фактически представляет последовательность бит.

Двоичная система

Поскольку бит может иметь только два значения — 1 и 0, то для записи битов применяют двоичную систему исчисления. Вообще система исчисления представляет способ записи чисел. Например, в поседневной жизни мы пользуемся десятичной системой исчисления . Это значит, что основанием этой системы является число 10, а каждый символ числа может иметь 10 вариантов значений — от 0 до 9. В десятичной системе каждое число можно представить как сумму цифер чисел, умноженных на 10 в степени, соответствующей порядковому номеру цифры в этом числе (нумерация начинается с нуля). Например, стандартное число 123 можно представить следующим образом:

12310 = 1 * 102 + 2 * 101 + 3 * 100 = 100 + 20 + 3

Или возьмем другое десятичное число — 123,45

123,4510 = 1 * 102 + 2 * 101 + 3 * 100 + 4 * 10-1 + 5 * 10-2 = 100 + 20 + 3 + 0,4 + 0,05

В двоичной системе каждый символ числа может иметь только два значения — 1 и 0, например, число 1101. Чтобы перевести число из двоичной системы в десятичную умножаем значение каждого бита (1 или 0) на число 2 в степени, равной номеру бита (нумерация битов идет от нуля):

// перевод двоичного числа 1101 в десятичную систему 1 * 23 + 1 * 22 + 0 * 21 + 1 * 20 = 1 * 8 + 1 * 4 + 0 * 2 + 1 * 1 = 8 + 4 + 0 + 1 = 13

Перевод десятичного числа в двоичную систему выглядит несколько сложнее. Стандартный алгоритм преобразования подразумевает деление числа и результатов последующих делений на 2 и помещение остатков от деления в результат. Например, переведем десятичное число 13 в двоичную систему:

// перевод десятичного числа 13 в двоичную систему 13 / 2 = 6 // остаток 1 (13 - 6 *2 = 1) 6 / 2 = 3 // остаток 0 (6 - 3 *2 = 0) 3 / 2 = 1 // остаток 1 (3 - 1 *2 = 1) 1 / 2 = 0 // остаток 1 (1 - 0 *2 = 1)

Общий алгоритм состоит в последовательном делении числа и результатов деления на 2 и получение остатков, пока не дойдем до 0. Затем выстраиваем остатки в линию в обратном порядке и таким образом формируем двоичное представление числа. Конкретно в данном случае по шагам:

  1. Делим число 13 на 2. Результат деления — 6, остаток от деления — 1 (так как 13 — 6 *2 = 1)
  2. Далее делим результат предыдущей операции деления — число 6 на 2. Результат деления — 3, остаток от деления — 0
  3. Делим результат предыдущей операции деления — число 3 на 2. Результат деления — 1, остаток от деления — 1
  4. Делим результат предыдущей операции деления — число 1 на 2. Результат деления — 0, остаток от деления — 1
  5. Последний результат деления равен 0, поэтому завершаем процесс и выстраиваем остатки от операций делений, начиная с последнего — 1101

Шестнадцатиричная система

Если число большое, то запись двоичных чисел может быть довольно длинной и поэтому не очень удобной. Например, число 23410 в двоичной системе равно 111010102 . И для упрощения работы с двоичными числами применяется шестнадцатеричная система.

В шестнадцатеричной системе счисления двоичные числа разделены на группы по 4 бита. При 4 битах в группе количество возможных значений равно 24 или 16. Первым 10 из этих 16 чисел присваиваются цифры 0–9, а последним 6 — буквы A-F:

Двоичное число 11101010 можно представить более компактно, разбив его на две 4-битные группы (1110 и 1010) и записав их в виде шестнадцатеричных цифр EA .

Алгоритм перевода из шестнадцатеричной системы в десятичную и обратно тот же, что и для двоичной, только вместо 2 используется число 16. Например, шестнадцатеричное число E6 можно представить следующим образом:

e6 = e * 161 + 6 * 160 = 14 * 16 + 6 = 23010 (десятичная система) = 1110 01102 (двоичная система)

А чтобы получить из 10-тичного числа 16-ричное, делим число на 16 и получаем остатки:

// перевод десятичного числа 230 в шестнадцатеричную систему 230 / 16 = 14 // остаток 6 (230 - 16 * 14 = 230 - 224) 14 / 16 = 0 // остаток 14 или E в 16-й системе // результат 0xE6

Чтобы указать, что число шестнадцатеричное, перед ним указываются символы 0X или 0x , например, 0xE6

Стоит отметить, что 4 бита, которые соответствуют одной шестнадцатеричной цифре, называется nibble или полубайт(слог, тертрада)

При работе с разными системами счисления легко запутаться. Например, какую систему в реальности представляет число 1010 ? Оно может равным образом представлять и десятичную, и двоичную, и шестнадцатеричную. И чтобы указать, что число относится к определенной системе счисления, используют различные обозначения. Так, для указания, что число является двоичным, перед число обычно ставится префикс 0b :

0b1010 - двоичное число (в десятичной системе равно 10, а в шестнадцатеричной - A)

Чтобы указать, что число является шестнадцатеричным, перед число обычно ставится префикс 0x :

0x1010 - шестнадцатеричное число (в десятичной системе равно 4112, а в двоичной - 1000000010000)

Представление отрицательных чисел

Для представления отрицательных чисел обычно применяется two’s complement ( дополнение до 2 ). С точки зрения математики чтобы получить отрицательный аналог числа надо от 0 (нуля) вычесть это число. Например, для получения -1 надо произвести операцию 0 — 1 = -1 . С точки зрения архитектуры компьютера в качестве 0 выступает число 2 N . В данном случае степень N представляет количество битов в числе.

Например, наше число состоит из 8 бит (1 байт), наподобие 0000 0001 (1 в десятичной системе). И мы хотим получить число -1. Для этого выполняем следующую операцию:

28 - 1 = 256 - 1 = 255

Но 255 — это в десятичной системе. А как это будет выглядеть в двоичной системе:

28 - 1 = 10000 0000 - 0000 0001 = 1111 1111

Таким образом, для 8 битное отрицательное число -1 в двоичной системе будет представлять 1111 1111

Аналогичная операция в шестнадцатеричной системе:

28 - 1 = 0x100 - 1 = 0xFF

Если же мы выполним обратную операцию — к 1111 1111 прибавим изначальное число 0000 0001 , то мы получим степень двойки. Поэтому подобное представление отрицательных чисел и называется дополнение до 2-х.

Простой способ получить из положительного числа отрицательного и наборот (то есть фактически умножение на -1) заключается в том, чтобы инвертировать биты — биты 0 поменять на 1, а 1 на 0, и затем прибавить 1. Например, получим число -3. Для этого сначала возьмем двоичное представление числа 3:

310 = 0000 00112 
~0000 0011 = 1111 1100
1111 1100 + 1 = 1111 1101

Таким образом, число 1111 1101 является двоичным представлением числа -3, что в шестнадцатеричной системе аналогично 0xFD

Другой пример, число 1 в двоичной системе равно 0b0000001 . Чтобы получить число -1, сначала инвертируем биты:

~0000 0001 = 1111 1110

Далее прибавляем 1:

1111 1110 + 1 = 1111 1111

То есть число -1 в двоичной системе равно 1111 1111 или 0xFF (в шестнадцатеричной системе)

Подобным образом можно получить обратно число 1:

~1111 1111 = 0000 0000 0000 0000 + 1 = 0000 0001

Соответственно, в зависимости от того, какое именно это число — положительное или отрицательно, интерпретировать это число можно по разному. Например, если число 1111 1111 рассматривается как положительное, то в десятичной системе оно равно 255. Если же оно рассматривается как отрицательное, то в десятичной системе оно равно -1.

Таким образом, 8-битные числа со знаком охватывают диапазон от -128 до 127, а 8-битные числа без знака — от 0 до 255.

Инструкции

Основу программы на ассемблере составляют инструкции — некоторые действия, например, сложение двух значений, помещение в регистр значения и т.д. При выполнении программы процессор выбирает и интерпретирует каждую инструкцию. Как и все данные, каждая инструкция, каждое действие в программе представляет последовательность битов. Каждой инструкции сопоставляется определенный машинный двоичный код, который также называется кодом инструкции или кодом операции (опкод, opcode).

Код операции — это один байт, определяющий основную операцию инструкции. Например, инструкция, которая копирует в регистр RAX число 1, имеет опкод C7 в шестнадцатеричной форме или 11000111 в двоичной форме. В зависимости от инструкции, ее операндов опкод меняется. Например, инструкция, которая копирует в регистр EAX число 1, имеет опкод B8 в шестнадцатеричной форме или 10111000 в двоичной форме. К опкодам инструкций следует добавить коды/значения операндов — регистра и чисел.

Написание машинного кода вручную возможно, но излишне громоздко. На практике вместо опкодов применяются так называемые мнемоники — человекочитаемые названия инструкций. Например, инструкция, которая копирует в регистр некоторое значение, имеет мнемонику mov (от слова «move» — помещать, поместить). А чтобы скопировать в регистр RAX число 1, нам достаточно написано команду

mov rax, 1

А чтобы скопировать в регистр EAX число 1, нам достаточно написано команду

mov eax, 1

Это довольно удобнее, чем в бинарной форме вводить команды.

Программа состоит из набора подобных инструкций. Процессор запускает программы через цикл выборки-выполнения (fetch-execute cycle). Компьютер считывает по одной инструкции за раз. Для этого процессор обращается к специальному регистру — указателю команд (или регистр IP), который также называется программным счетчиком (или PC) и который хранит адрес инструкции для выполнения. По сути, компьютер выполняет бесконечный цикл следующих операций:

  1. Считывает инструкцию с адреса памяти, указанного указателем инструкции — регистром IP/PC
  2. Декодирует инструкцию (т. е. выясняет, что означает инструкция)
  3. Перемещает указатель инструкций (регистр IP/PC) к следующей инструкции
  4. Выполняет указанную инструкцию

Сколько бит занимает число

Калькулятор подсчитывает число бит, нужное для записи заданного целого числа в двоичном виде, число может быть очень большим.

Этот калькулятор можно использовать для подсчета знаков, необходимых для записи большого числа в двоичном виде (число бит). Также выдается какой объем памяти требуется для хранения этого числа в памяти компьютера (число байт). Кроме этого калькулятор определяет число разрядов для вывода числа в восьмеричном, в десятичном и шестнадцатеричном виде и выводит исходное число в этих системах счисления.

Сколько бит в большом целом

Большое целое
Рассчитать
Двоичное представление
Восьмеричных разрядов
Восьмеричное представление
Десятичных разрядов
Десятичное представление
Шестнадцатеричных разрядов
Шестнадцатеричный код
Число байт
Ссылка Сохранить Виджет

Ограничения на длину числа нет — максимум зависит только от ресурсов вашего компьютера.
К примеру, число с одной тысячей нулей можно ввести вот так: 123E1000

Калькулятор вычисляет число двоичных разрядов путем преобразования числа в двоичную строку и последующего вычисления ее длины.
На практике такой способ неэффективен. Реализация более эффективного алгоритма поиска позиции старшего значащего бита во многом зависит от представления числа в памяти компьютера и сложности выполнения тех или иных операций.
Например, математически число бит можно вычислить путем округления в большую сторону логарифма по основанию 2 от заданного числа плюс 1:

Битовое представление чисел

Так как на уровне схем почти вся логика бинарная, ровно такое представление и используется для хранения чисел в компьютерах: каждая целочисленная переменная указывает на какую-то ячейку из 8 ( char ), 16 ( short ), 32 ( int ) или 64 ( long long ) бит.

#Эндианность

Единственная неоднозначность в таком формате возникает с порядком хранения битов — также называемый эндианностью. Зависимости от архитектуры он может быть разным:

  • При схеме little-endian сначала идут младшие биты. Например, число $42_$ будет храниться так: $010101$.
  • При записи в формате big-endian сначала идут старшие биты. Все примеры из начала статьи даны в big-endian формате.

Хотя big-endian более естественный для понимания — на бумаге мы ровно так обычно и записываем бинарные числа — по разным причинам на большинстве современных процессоров по умолчанию используется little endian.

Иными словами, «$i$-тый бит» означает «$i$-тый младший» или «$i$-тый справа», но на бумаге мы ничего не инвертируем и записываем двоичные числа стандартным образом.

#Битовые операции

Помимо арифметических операций, с числами можно делать и битовые, которые интерпретируют их просто как последовательность битов.

#Сдвиги

Битовую запись числа можно «сдвигать» влево ( x > y ), что эквивалентно умножению или делению на степень двойки с округлением вниз.

Обычное умножение и деление — не самые быстрые операции, однако все битовые сдвиги всегда работают ровно за один такт. Как следствие, умножение и деление на какую-то фиксированную степень двойки всегда работает быстро — даже если вы не используете сдвиги явно, компилятор скорее всего будет проводить подобную оптимизацию.

#Побитовые операции

Помимо && , || и ! , существуют их побитовые версии, которые применяют соответствующую логическую операцию к целым последовательностям битов: & , | , ~ .

Также помимо них есть ещё операция исключающего «или» (XOR), которая записывается как ^ .

  • $13$ & $7$ = $1101_2$ & $0111_2$ = $0101_2$ = $5$
  • $17$ | $10$ = $10001_2$ | $01010_2$ = $11011_2$ = $27$
  • $17$ ^ $9$ = $10001_2$ ^ $01001_2$ = $11000_2$ = $24$

Все побитовые операции тоже работают за один такт, вне зависимости от типа данных. Для больших не вмещающихся в один регистр битовых последовательностей существует битсет.

#Маски

Бинарные последовательности можно поставить в соответствие подмножествам какого-то фиксированного множества: если на $i$-той позиции стоит единица, то значит $i$-тый элемент входит множество, а иначе не входит.

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

#Выделить i-й бит числа

Это часто используется для проверки, принадлежит ли $i$-тый элемент множеству:

Напомним, что нумерация идет с младших бит и начинается с нуля.

#Получить число, состоящее из k единиц

#Инвертировать все биты числа

#Добавить i-й элемент в множество

#Удалить $i$-й элемент из множества

#Удалить i-й элемент из множества, если он есть

Также добавляет этот элемент, если его нет.

#Знаковые числа

Целочисленные переменные делятся на два типа — знаковые (signed) и беззнаковые (unsigned).

Если сложить две unsigned int переменные, сумма которых превосходит $2^$, произойдет переполнение: сумму нельзя будет представить точно, и поэтому вместо неё результатом будут только нижние 32 бит. Все операции с беззнаковыми числами как бы проходят по модулю какой-то степени двойки.

Знаковые же типы нужны для хранения значений, которые могут быть и отрицательными. Для этого нужно выделить один бит для хранение знака — отрицательное ли число или нет — немного пожертвовав верхней границей представимых чисел: теперь самое большое представимое число это $2^-1$, а не $2^-1$.

Инженеры, которые работают над процессорами, ещё более ленивые, чем программисты — это мотивировано не только стремлением к упрощению, но и экономией транзисторов. Поэтому когда в signed типах происходит переполнение, результат в битовом представлении считается так же, как и в случае с unsigned числами. Если мы хотим ничего не менять в плане того, как работают unsigned числа, представление отрицательных чисел должно быть таким, что число $-x$ как бы вычитается из большой степени двойки:

  • Все неотрицательные числа записываются в точности как раньше.
  • У всех отрицательных чисел самый большой бит будет единичным.
  • Если прибавить к $2^-1$ единицу, то результатом будет $-2^$, представляемое как 10000000 (в целях изложения мы будем записывать 8 бит, хотя в int их 32).
  • Зная двоичную запись положительного числа x , запись -x можно получить как ~x + 1 .
  • -1 записывается как ~1 + 1 = 11111110 + 00000001 = 11111111 .
  • -42 записывается как ~42 + 1 = 11010101 + 00000001 = 11010110 .
  • После -1 = 11111111 идет 0 = -1 + 1 = 11111111 + 00000001 = 00000000 .

Упражнение. Каких чисел больше: положительных или отрицательных?

Осторожно. В стандарте C/C++ прописано, что переполнение знаковых переменных приводит к undefined behavior, поэтому полагаться на описанную логику переполнения нельзя, хотя равно это скорее всего и произойдет.

#128-битные числа

Общих регистров размера больше 64 в процессорах нет, однако умножение и несколько смежных инструкций могут использовать два последовательных регистра как один большой. Это позволяет быстро перемножать два 64-битных числа и получать 128-битный результат, разделенный на нижние биты и верхние.

Это весьма специфичная операция, и поэтому в языках программирования нет полноценной поддержки 128-битных переменных. В C++ однако есть «костыль» — тип __int128_t — который фактически просто оборачивает пару из двух 64-битных регистров и поддерживает арифметические операции с ними.

Базовые арифметические операции с ним чуть медленнее, его нельзя напрямую печатать, и деление и прочие сложные операции будут вызывать отдельную библиотеку и поэтому работать очень долго, однако в некоторых ситуациях он оказывается очень полезен.

Как конвертировать число в биты

В результате получаю 1 = 110001,3 = 110011 и т.д. Откуда появляются 2 единицы в начале и как от них избавится?

Отслеживать
задан 5 мая 2019 в 10:11
65 12 12 бронзовых знаков

Строк или чисел, вижу строки, а читаю про числа. Странноватенько. Если строки то str.Select(i => Convert.ToString(i, 2)) если реальные числа, то: (byte)(num >> 8) или BitConverter.GetBytes(num)

5 мая 2019 в 10:18

@And Если я использую (byte)(num >> 8) то в ответе получаю нули вместо значений,а если BitConverter.GetBytes(num) то System.Byte[] . Пожалуйста,можете привести пример?

5 мая 2019 в 10:44

Что-что нужно сделать?? Convert.ToString(textBox1.Text); ясности не добавляет. 110001b — это ASCII-код символа «1»

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *