Что будет, если в качестве основания системы счисления поставить отрицательное число?
Введение
Возьмем какое-то число a, и представим его в двоичнои представлении
1 | a = aₙ⋅2ⁿ + aₙ₋₁⋅2ⁿ⁻¹ + ... + a₁⋅2¹ + a₀⋅2⁰ |
Все цифры aᵢ ∈ {0, 1}, и такое разложение единственно для положительных чисел. Для отрицательных чисел же используется разные способы:
- прямой код - бит для знака
- обратный код - все биты инвертируются
- дополнительный код - инвертируются биты и прибавляется единица
Дополнительный код достаточно удобный, поскольку арифметические операции не требуют проверки для знака числа.
В нем слегка сложным будет операция расширения, т.е. когда число хранится, например, в одном байте, а мы хотим его превратить в четырехбайтовое.
1 | char a = -2; // 1111 1110 |
Для этого надо сначала определить знак, и все дополнительные биты выставить либо в 1, либо в 0.
Но что если мы попробуем в качестве основания системы счисления использовать -2?
Тогда представление числа будет таким:
1 | a = aₙ⋅(-2)ⁿ + aₙ₋₁⋅(-2)ⁿ⁻¹ + ... + a₁⋅(-2)¹ + a₀⋅(-2)⁰ |
При этом по-прежнему оставляем цифры aᵢ ∈ {0, 1}
-2 в нечетной степени даст отрицательное число, а в четной - положительное, и тогда мы будем получать то положительные, то отрицательные числа без всяких дополнительных кодов.
Посмотрим, какие значения получаются при разных комбинациях битов и их разных количествах
Диапазоны значений
Для одного бита
| Двоичное | Формула | Значение |
|---|---|---|
| 0 | 0⋅(-2)⁰ = 0 | 0 |
| 1 | 1⋅(-2)⁰ = 1 | 1 |
Покрывает интервал [0, 1]
Добавим еще бит. (-2)¹ = -2
| Двоичное | Формула | Значение |
|---|---|---|
| 10 | 1⋅(-2)¹ + 0⋅(-2)⁰ = -2 + 0 | -2 |
| 11 | 1⋅(-2)¹ + 1⋅(-2)⁰ = -2 + 1 | -1 |
Интервал значений расширился до [-2, 1], т.е по сравнению с однобитовыми добавились представления отрицательных чисел -2, -1
Еще бит. (-2)² = 4
| Двоичное | Формула | Значение |
|---|---|---|
| 100 | 1⋅(-2)² + 0⋅(-2)¹ + 0⋅(-2)⁰ = 4 - 0 + 0 | 4 |
| 101 | 1⋅(-2)² + 0⋅(-2)¹ + 1⋅(-2)⁰ = 4 - 0 + 1 | 5 |
| 110 | 1⋅(-2)² + 1⋅(-2)¹ + 0⋅(-2)⁰ = 4 - 2 + 0 | 2 |
| 111 | 1⋅(-2)² + 1⋅(-2)¹ + 1⋅(-2)⁰ = 4 - 2 + 1 | 3 |
С тремя битами интервал [-2, 1] расширился в положительную сторону, до [-2, 5]
Аналогично будет с четырьмя битами, интервал расширится на 8 отрицательных значений и станет [-10, 5]
| Количество бит | Интервал | Длина интервала |
|---|---|---|
| 1 | 0 .. 1 | 2 |
| 2 | -2 .. 1 | 4 |
| 3 | -2 .. 5 | 8 |
| 4 | -10 .. 5 | 16 |
| 5 | -10 .. 21 | 31 |
| 6 | -42 .. 21 | 64 |
| 7 | -42 .. 85 | 128 |
| 8 | -170 .. 85 | 256 |
Профит от такого представления, кажется, только один - легко расширить количество бит хранения, например, с байта до четырех байт. Для этого просто заполняем нулями дополнительные байты.
Отсортированные числа
Если выписать минусдвоичные числа и отсортировать, получится такая табличка
| negbin | Значение |
|---|---|
| 1010 | -10 |
| 1011 | -9 |
| 1000 | -8 |
| 1001 | -7 |
| 1110 | -6 |
| 1111 | -5 |
| 1100 | -4 |
| 1101 | -3 |
| 0010 | -2 |
| 0011 | -1 |
| 0000 | 0 |
| 0001 | 1 |
| 0110 | 2 |
| 0111 | 3 |
| 0100 | 4 |
| 0101 | 5 |
Сравнение
TBD
Противоположное число
TBD
Сумма
Когда мы суммируем двоичные числа, алгоритм достаточно прямолинеен - складываем побитно, начиная с младшего, и, если произошло переполнение, то учитываем его.
Для минусдвоичного представления все становится чуть более запутанным
1 | a = aₙ⋅2ⁿ + aₙ₋₁⋅2ⁿ⁻¹ + ... + a₁⋅2¹ + a₀⋅2⁰ |
Младший бит просуммируется нормально
1 | с₀ = a₀ + b₀ (mod 2) |
Если оба a₀ и b₀ равны 1, то надо выставить флаг переноса (CF).
И следующий бит должен учитывать этот перенос. Но у следующего бита всегда знак противоположный, поэтому берем CF со знаком минус.
1 | с₁ = a₁ + b₁ - CF (mod 2) |
с₁ может получиться -1 или 2.
- Если 2, просто пишем 0 и выставляем CF в 1.
- Если -1 (
a₁ = 0, b₁ = 0, CF = 1) - результат должен быть 11 (это как раз -1₁₀). Пишем 1, а в CF сохраняем -1.
Для следующих битов CF может быть равен -1. Так что c₂ = a₂ + b₂ - CF может получиться значение 3 (111₋₂). В этом случае пишем 1, в carry сохраняем -1 (это в минусдвоичной 11₋₂, т.е как раз оставшиеся единички).
В общем, получается что CF может быть 0, 1 или -1.
При сложении в столбик удобно рисовать CF над следующим столбцом в виде • (если CF = 1) или в виде ◦ (если CF = -1).
Все варианты можно свести в табличку
Таблица преобразования при сложении
| CF | aᵢ | bᵢ | cᵢ | CF | |
|---|---|---|---|---|---|
| 0 | 0 | = | 0 | ||
| 0 | 1 | = | 1 | ||
| 1 | 1 | = | 0 | • | |
| • | 0 | 0 | = | 1 | ◦ |
| • | 0 | 1 | = | 0 | |
| • | 1 | 1 | = | 1 | |
| ◦ | 0 | 0 | = | 1 | |
| ◦ | 0 | 1 | = | 0 | • |
| ◦ | 1 | 1 | = | 1 | • |
Примеры суммирования
1 + -1 = 0
1 | • |
1 + 1 = 2
1 | ◦• |
- сначала складываем 1 и 1, получаем 0 и CF=•
- Затем • + 0 + 0 => пишем 1 и CF=◦
- Старший бит: ◦ + 0 + 0 => пишем 1, CF пустой
5 + 1 = 6
1 | ◦•◦• |
- Складываем 1+1, получаем 0 и CF=•
- Затем •+0+0 => пишем 1 и CF=◦
- Затем ◦+1+0 => пишем 0 и CF=•
- Основные цифры кончились, но остался СF: •+0+0 => пишем 1 и CF=◦
- Старший бит: ◦+0+0 => пишем 1, CF пустой
5 + 5 = 10
1 | ◦•◦• |
Отличается от предыдущего только во третьем бите, тут ◦+1+1 => пишем 1 и CF=•
Умножение
TBD
Примечание. Таблица пятибитных негбинарных
1 | 0 0 |