Подписанные и неподписанные целые числа

395

Правильно ли я сказать, что разница между целым числом со знаком и без знака такова:

  1. Без знака может иметь большее положительное значение, а не отрицательное значение.
  2. Неподписанный использует начальный бит как часть значения, в то время как подписанная версия использует самый левый бит, чтобы определить, является ли число положительным или отрицательным.
  3. целые числа со знаком могут содержать как положительные, так и отрицательные числа.

Есть другие отличия?

Шимми Вайцхандлер
источник
6
Поскольку 0 не является ни положительным, ни отрицательным , более целесообразно использовать термин неотрицательное значение вместо положительного значения для целых чисел без знака.
Даниил

Ответы:

344

Без знака может иметь большее положительное значение, а не отрицательное значение.

Да.

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

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

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

да

Greg
источник
Я не уверен, что это именно тот текст, но я нашел другую ссылку. Перейдите на 9-ю страницу PDF (на самом деле это 38-я страница книги), и вы увидите раздел «Представление данных» (раздел 1.3). В нем есть объяснение всего сказанного выше. lms.uop.edu.jo/lms/pluginfile.php/2420/mod_resource/content/1/…
WeirdElfB0y
92

Я пойду в различия на аппаратном уровне, на x86. Это в основном не имеет значения, если вы не пишете компилятор или не используете язык ассемблера. Но это приятно знать.

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

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

Во-первых, у двух чисел дополнения есть свойство, что сложение и вычитание такие же, как для чисел без знака. Не имеет значения, являются ли числа положительными или отрицательными. (Таким образом, вы просто идете вперед ADDи SUBваши номера без беспокойства.)

Различия начинают проявляться, когда дело доходит до сравнений. В x86 есть простой способ их различения: выше / ниже указывает сравнение без знака и больше / меньше, чем сравнение со знаком. (Например, JAEозначает «Перейти, если выше или равно» и без знака.)

Есть также два набора команд умножения и деления для работы со знаковыми и беззнаковыми целыми числами.

И наконец: если вы хотите проверить, скажем, переполнение, вы бы сделали это по-разному для чисел со знаком и для чисел без знака.

Artelius
источник
Что вы подразумеваете под числами без знака и со знаком, я хочу спросить, пишу ли я без знака int a = 2 и со знаком int b = 2, так что они оба являются знаковыми или без знака, зависит ли число подписываемых или без знака от типа мы назначаем его или зависит от того, имеет ли он отрицательный знак или нет? Это беспокоило меня некоторое время.
Сурадж Джейн
@SurajJain подписаны и без знака , относятся к типам. Они указывают , является ли это возможно для переменной или выражение , чтобы иметь отрицательное значение.
Артелиус
У меня есть следующие сомнения, я задал вопрос, но пока нет удовлетворительного ответа, посмотрите на него здесь, stackoverflow.com/questions/41399092/…
Сурадж Джейн
62

Он только спросил о подписанных и неподписанных. Не знаю, почему люди добавляют дополнительные вещи в это. Позвольте мне сказать вам ответ.

  1. Без знака: состоит только из неотрицательных значений, то есть от 0 до 255.

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

    • От 0 до +127
    • -1 до -128

И это объяснение о 8-битной системе счисления.

Ашиш Кумар
источник
17

Всего несколько баллов за полноту:

  • этот ответ обсуждает только целочисленные представления. Там могут быть другие ответы для плавающей запятой;

  • представление отрицательного числа может варьироваться. Наиболее распространенным (на сегодняшний день - почти универсальным сегодня) в использовании сегодня является дополнение двух . Другие представления включают в себя дополнение (довольно редкое) и величину со знаком (исчезающе редко - возможно, только для музейных экспонатов), которая просто использует старший бит в качестве индикатора знака, а оставшиеся биты представляют абсолютное значение числа.

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

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

Майкл Берр
источник
Если я напишу без знака int a = -2 и со знаком int b = -2, будет ли базовое представление таким же, я знаю, что не хорошо иметь число без знака с отрицательным значением, но, тем не менее, если я его передам, что будет основное представление?
Сурадж Джейн
1
Незначительный niggle: знак и величина используются в IEEE с плавающей запятой, так что это на самом деле довольно часто. :-)
alastair
14

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

Например, глядя на 8-битное число:

значения без знака0 для255

Подписанные значения от -128до127

Ин Сюн
источник
11

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

Джаспер Беккерс
источник
Это вещь с прямым порядком байтов и с прямым порядком байтов?
vIceBerg
little-big-endian имеет отношение к порядку байтов на платформе. Little endian может сделать 0xFF 0xFE 0x7F, в то время как big endian сделает 0x7F 0xFE 0xFF.
Джаспер Беккерс
10

Другое отличие заключается в том, что вы конвертируете между целыми числами разных размеров.

Например, если вы извлекаете целое число из потока байтов (скажем, 16 битов для простоты) со значениями без знака, вы можете сделать:

i = ((int) b[j]) << 8 | b[j+1]

(вероятно, должен привести 2- й байт, но я предполагаю, что компилятор сделает правильную вещь)

Со значениями со знаком вам придется беспокоиться о расширении знака и делать:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
Майк Глин
источник
5

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

toddk
источник
4

Помимо того, что говорили другие, в C вы не можете переполнить целое число без знака; поведение определено как модульная арифметика. Вы можете переполнить целое число со знаком и, теоретически (хотя на практике это не актуально для современных основных систем), переполнение может вызвать ошибку (возможно, аналогичную ошибке деления на ноль).

Джонатан Леффлер
источник
1
Обратите внимание, что целочисленное переполнение со знаком действительно запускает неопределенное поведение, и современные компиляторы очень агрессивно оценивают это и используют его для изменения вашей программы неожиданными, но технически обоснованными способами, поскольку им разрешено предполагать, что неопределенное поведение не произойдет - грубо говоря. Это гораздо более серьезная проблема, чем 7 лет назад.
Джонатан Леффлер
4
  1. Да, целое число без знака может хранить большое значение.
  2. Нет, есть разные способы показать положительные и отрицательные значения.
  3. Да, целое число со знаком может содержать как положительные, так и отрицательные значения.
Bhavesh
источник
4

(в ответ на второй вопрос) Используя только знаковый бит (а не 2-е дополнение), вы можете получить -0. Не очень красиво.

Райан Родемойер
источник
Просто чтобы добавить к этому ответу, в основном это означает, что 10 == 00, где оба эти числа являются основанием 2.
4

Целые числа со знаком в C представляют числа. Если aи bявляются переменными целочисленных типов со знаком, стандарт никогда не потребует, чтобы компилятор сохранял выражение a+=bво aчто-либо, кроме арифметической суммы их соответствующих значений. Чтобы быть уверенным, что если арифметическая сумма не поместится a, процессор, возможно, не сможет поместить ее туда, но стандарт не потребует от компилятора усекать или переносить значение, или делать что-либо еще в этом отношении, если значения превышают пределы для их типов. Обратите внимание, что, хотя стандарт не требует этого, реализациям C разрешено перехватывать арифметические переполнения со знаковыми значениями.

Целые числа без знака в C ведут себя как абстрактные алгебраические кольца целых чисел, которые являются конгруэнтными по модулю некоторой степени двух, за исключением случаев, когда требуется преобразование или операции с большими типами. Преобразование целого числа любого размера в 32-разрядный тип без знака приведет к члену, соответствующему вещам, которые соответствуют этому целочисленному модулю 4 294 967 296. Причина, по которой вычитание 3 из 2 дает 4 294 967 295, состоит в том, что добавление чего-то равного 3 к чему-то равному 4 294 967 295 даст что-то равное 2.

Абстрактные типы алгебраических колец часто очень удобны; к сожалению, C использует подпись как решающий фактор того, должен ли тип вести себя как кольцо. Хуже того, значения без знака обрабатываются как числа, а не как члены кольца при преобразовании в более крупные типы, а значения без знака меньше, чем intпреобразуются в числа, когда над ними выполняется любая арифметика. Если vэто uint32_tчто равняется 4,294,967,294, то v*=v;должен сделать v=4. К сожалению, если intесть 64 бита, то неясно, что v*=v;может сделать.

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

Supercat
источник
3

Целые числа без знака гораздо чаще попадают в конкретную ловушку, чем целые числа со знаком. Эта ловушка связана с тем фактом, что, хотя приведенные выше пункты 1 и 3 являются правильными, обоим типам целых чисел может быть присвоено значение за пределами того, что он может «удерживать», и он будет преобразован без вывода сообщений.

unsigned int ui = -1;
signed int si = -1;

if (ui < 0) {
    printf("unsigned < 0\n");
}
if (si < 0) {
    printf("signed < 0\n");
}
if (ui == si) {
    printf("%d == %d\n", ui, si);
    printf("%ud == %ud\n", ui, si);
}

Когда вы запустите это, вы получите следующий вывод, даже если оба значения были присвоены -1 и были объявлены по-разному.

signed < 0
-1 == -1
4294967295d == 4294967295d
Мэтью
источник
0

Единственное гарантированное различие между значением со знаком и без знака в C состоит в том, что значение со знаком может быть отрицательным, 0 или положительным, тогда как значение без знака может быть только 0 или положительным. Проблема в том, что C не определяет формат типов (поэтому вы не знаете, что ваши целые числа в дополнении до двух). Строго говоря, первые два пункта, которые вы упомянули, неверны.

Яснее
источник
0

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

Фахад Наим
источник