В большинстве, если не во всех языках программирования, вы можете иметь положительные и отрицательные целые числа. Эти значения никогда не имеют дробной части, что означает, что они не имеют десятичных знаков. Их также обычно называют целыми числами со знаком, потому что у них есть представляющий бит в памяти, который сообщает, находятся ли они ниже или выше и равны нулю, что означает (-) или (+).
Когда числа никогда не должны иметь отрицательное значение, существует представление, называемое целым числом без знака. Это представление занимает все пространство памяти, которое могли бы занимать отрицательные значения, и добавляет их к положительным значениям.
В языке C их объявления выглядят следующим образом:
/* Signed Integer */ int n = -2; /* Unsigned Integer */ unsigned int m = 2;
Это также может иметь небольшую вариацию с модификатором, называемым коротким или длинным, что в основном позволяет переменным хранить еще больше данных. В следующей таблице показаны диапазон значений и размер хранилища таких переменных на языке C.
Двоичное представление
Числовые значения, хранящиеся в памяти, представлены в виде битов (0 или 1) в группах байтов (8 бит).
Число, такое как 2, сохраняется в памяти как
00000000 00000000 00000000 00000010
Что означает 4 байта памяти для целого числа со знаком.
Но как насчет отрицательных чисел? Как язык C понимает, что число имеет отрицательное значение или нет?
Здесь используется двойное дополнение двоичного файла. Дополнение — это преобразование двоичного представления числа, которое позволяет отображать отрицательные значения, для понимания дополнения до двух мы должны сначала увидеть дополнение до единицы.
Дополнение 1 или Дополнение 1
Это метод, используемый для представления отрицательных двоичных чисел в переменных типа со знаком. В дополнении положительные числа (также известные как недополнения) остаются неизменными.
С другой стороны, отрицательные числа представлены путем инвертирования двоичного представления положительного числа. Поскольку положительные числа всегда начинаются с «0», дополнение всегда будет начинаться с «1», чтобы указать отрицательное число.
Пример:
Если бы мы хотели представить -1, нам нужно было бы взять инверсию 0. Для этого мы можем использовать побитовый оператор ~ (дополнение до единицы), который инвертирует все биты переменной.
На языке C, используя printf, мы получили бы:
#include <stdio.h> int main() { /* Binary of 0: 00000000 */ printf("Value 0: %d\n", 0); /* Binary of ~0: 11111111 */ printf("Value ~0: %d\n", ~0); /* Binary of 1: 00000001 */ printf("Value 1: %d\n", 1); /* Binary of ~1: 11111110 */ printf("Value ~1%d\n", ~1); /* Binary of 2: 00000010*/ printf("Value 2: %d\n", 2); /* Binary of ~2: 11111101*/ printf("Value ~2: %d\n", ~2); return 0; } Value 0: 0 Value ~0: -1 Value 1: 1 Value ~1: -2 Value 2: 2 Value ~2: -3
Проблема с этим представлением заключается в том, что 0 имеет как положительное, так и отрицательное значение -0 и +0.
Дополнение до двух или Дополнение до двух
Это еще один метод, подобный дополнению до единицы, для представления отрицательных двоичных чисел при наличии переменной типа со знаком. В дополнении до двух положительные числа остаются неизменными по сравнению с их базовым двоичным представлением. Однако отрицательное число представлено двоичным числом, которое при добавлении к соответствующему положительному эквиваленту дает ноль. Проще говоря, дополнение числа до двух равно его дополнению до единицы + 1.
Основное преимущество дополнения до двух перед дополнением до единицы заключается в том, что проще сгенерировать дополнение до двух для двоичного числа со знаком. Следовательно, арифметические операции легче выполнять, когда числа представлены таким образом. Кроме того, 0 имеет единственное положительное (+) представление.
Если, например, у нас есть число 5, то его двоичное представление будет таким:
00101 Obtaining the One´s complement would result in 01010 And adding 1 (00001) would result in 01011 Positive 5 Would have a first bit in 0 and Negative 5 would have this bit in 1 01011 (+5) 11011 (-5)
Это будет визуализировано следующим образом:
MSB всегда равен 1 в случае отрицательных чисел и 0 в случае положительных чисел.
Диапазон чисел:
Значения, представленные таким образом в nразрядном регистре памяти, могут иметь положительное число до
{[2 ^ (n-1)] - 1}
, и отрицательное число от
-[2^(n-1)].
Арифметика с дополнением до 2:
Одним из преимуществ представления значений со знаком с дополнением до 2 является возможность легкого выполнения двоичной арифметики над числами со знаком или без знака. В результате получается правильное дополнение до двойки.
Дополнение:
Мы можем просто преобразовать числа, с которыми мы хотим работать, в дополнение до 2, а затем выполнить простое сложение с основанием 2.
0000 1000 + 1111 1101 ---------- Carry 1 <-0000 0101 = (+5)
Поскольку перенос равен 1, то число положительное (бит со знаком).
Здесь перенос равен 1, но он выходит за пределы байта, поэтому он не учитывается в ответе, и результатом является положительное число длиной в один байт.
Вычитание:
Подобно сложению, но здесь вычитаемое сначала преобразуется в отрицательную форму, а затем добавляется с уменьшаемым.
Пример:
0000 1000 - 1111 0111 ---------- Carry 0<-1111 1111 = (-1)
Поскольку перенос равен 0, то число отрицательное (бит со знаком).
Умножение:
Это следует тем же правилам, что и базовое двоичное умножение.
Пример:
1111 1100 (+4) * 0000 0100 (-4) ---------- Carry 0<-1111 0000=(-16)
Поскольку перенос равен 0, то число отрицательное (бит со знаком).
Отдел:
Для деления это состоит из многократного повторения вычитания дополнения до двух.
- Сначала вычислите дополнение до 2 делителя, а затем этот преобразованный делитель должен быть добавлен к делимому.
- Теперь идет следующий цикл вычитания. Здесь частное заменяет делимое.
- Это повторяется снова и снова, пока частное не станет слишком маленьким или равным нулю. Если он не равен нулю, то он считается остатком.
Пример:
0000 0111 (+7) / 1111 1101 (-3) ---------- 0000 0100 = (+4) 0000 0100 (+4) / 1111 1101 (-3) ---------- 0000 0100 = (+1) Remainder
Знаковый бит равен 0, поэтому остаток положительный.
Переполнение:
Значения со знаком в языках программирования имеют проблему с размером
Когда значение со знаком превышает свой положительный предел, оно начинает показывать отрицательные числа с самого низкого возможного значения в памяти, а затем увеличивается. Это происходит обратно пропорционально отрицательным значениям. Когда целое число со знаком становится меньше минимально возможного числа в памяти, оно начинает показывать положительные значения, начиная с максимально возможного положительного числа, а затем уменьшаясь.
Если, например, у нас есть пределы -10 и 9 в памяти
- Значение -11 покажет 9
- Значение -12 покажет 8
И так далее…
- Значение 10 покажет -10
- Значение 11 покажет -9