Підписано проти непідписаних цілих чисел


395

Чи правильно я стверджую, що різниця між цілим числом, що підписується та не підписується, полягає в:

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

Будь-які інші відмінності?


6
Оскільки 0 не є ні позитивним, ні негативним , більш доцільним є використання терміна негативне значення замість додатного значення для непідписаних цілих чисел.
Даніель

Відповіді:


344

Непідписаний може містити більше позитивне значення, а не негативне значення.

Так.

Непідписаний використовує провідний біт як частину значення, тоді як підписана версія використовує ліворуч-біт, щоб визначити, чи є число позитивним чи негативним.

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

підписані цілі числа можуть містити як додатні, так і від’ємні числа.

Так


Я не впевнений, чи це саме такий текст, але я знайшов інше посилання. Перейдіть на 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означає "Перейти, якщо вище або дорівнює", і не підписується.)

Існує також два набори інструкцій на множення та ділення для роботи з підписаними та непідписаними цілими числами.

Нарешті: якщо ви хочете перевірити, скажімо, на переповнення, ви зробили б це по-різному для підписаних чи неподписаних номерів.


Що ви маєте на увазі під безпідписаними та підписаними номерами, що я хочу запитати, якщо я записую без підпису int a = 2 та підписаний int b = 2, тож вони підписані чи непідписані, чи залежить число підписаного чи неподписаного чи залежить від типу ми присвоюємо це, або залежить від того, має він негативний знак чи ні? Це вже давно клопоче мене.
Сурай Джайн

@SurajJain з підписами та без підпису стосуються типів. Вони вказують, чи можливо змінна чи вираз мати негативне значення.
Артелій

У мене є такі сумніви, я поставив запитання, поки немає задовільної відповіді, подивіться на це тут, stackoverflow.com/questions/41399092/…
Suraj Jain

62

Він запитував лише про підписані та без підпису. Не знаю, чому люди додають до цього зайві речі. Дозвольте сказати вам відповідь.

  1. Без підпису: Він складається лише з негативних значень, тобто від 0 до 255.

  2. Підписано: Він складається як з негативних, так і з позитивних значень, але в різних форматах

    • 0 до +127
    • Від -1 до -128

І це пояснення стосується 8-бітної системи числення.


17

Лише кілька балів для повноти:

  • ця відповідь обговорює лише цілі представлення. Для плаваючої точки можуть бути інші відповіді;

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

  • Використовуючи доповнення двох, змінна може представляти більший діапазон (на одне) від’ємних чисел, ніж додатні числа. Це пов’язано з тим, що нуль включається в «позитивні» числа (оскільки біт знаків не встановлений для нуля), але не від'ємні числа. Це означає, що абсолютне значення найменшого від’ємного числа не може бути представлене.

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


Якщо я напишу непідписаний int a = -2 та підписаний int b = -2, чи було б базовим представленням однаковим, я знаю, що непогано мати неподписане число, надавши від'ємне значення, але все ж, якщо я даю це, що буде основне представництво?
Сурай Джайн

1
Невеликий нігтя: знак і величина використовується в плаваючій точці IEEE, тому це насправді досить часто. :-)
alastair

14

Відповідно до того, що ми дізналися на уроці, підписані цілі числа можуть представляти як додатні, так і від’ємні числа, тоді як цілі числа, що не підписуються, є лише негативними.

Наприклад, дивлячись на 8-бітове число:

неподписані значення 0до255

Підписані значення від -128до127


11

Все, окрім пункту 2, правильно. Існує багато різних позначень для підписаних вкладишів, деякі реалізації використовують перші, інші використовують останні, а інші використовують щось зовсім інше. Все залежить від платформи, з якою ви працюєте.


Це та річ малого та великого ендіанів?
vIceBerg

маленький і великий ендіан пов'язаний з порядком байтів на платформі. Маленький ендіан може зробити 0xFF 0xFE 0x7F, тоді як великий ендіан зробить 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

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


4

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


1
Зауважте, що підписане ціле переповнення викликає не визначену поведінку, а сучасні компілятори надто агресивні щодо того, щоб помітити це та використовувати його для зміни вашої програми несподіваними, але технічно законними способами, оскільки їм дозволяється припускати, що невизначена поведінка не відбудеться - грубо кажучи. Це набагато більша проблема зараз, ніж це було 7 років тому.
Джонатан Леффлер

4
  1. Так, непідписане ціле число може зберігати велике значення.
  2. Ні, є різні способи відображення позитивних і негативних значень.
  3. Так, підписане ціле число може містити як позитивні, так і негативні значення.

4

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


Просто для додання цієї відповіді, це означає, що 10 == 00, де обидва ці числа є базовими 2.

4

Підписані цілі числа в C представляють числа. Якщо aі bє змінними цілих цілочисельних типів, стандарт ніколи не вимагатиме, щоб компілятор перетворив запас виразів a+=bу aщось інше, ніж арифметична сума їх відповідних значень. Щоб бути впевненим, якщо арифметична сума не вміститься a, процесор може не змогти її помістити, але стандарт не вимагає від компілятора усікання або перенесення значення або робити щось інше з цього питання, якщо значення перевищують межі для їх видів. Зауважте, що, хоча стандарт цього не вимагає, реалізаціям 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;можна зробити.

З огляду на стандартний такий, який він є, я б запропонував використовувати непідписані типи в ситуаціях, коли хочеться поведінки, пов'язаної з алгебраїчними кільцями, і підписаних типів, коли потрібно представляти числа. Прикро, що С намалював відзнаки так, як це зробив, але вони є такими, якими вони є.


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

Єдина гарантована різниця між підписаним та неподписаним значенням у С полягає в тому, що підписане значення може бути від'ємним, 0 або позитивним, тоді як неподписане може бути лише 0 або позитивним. Проблема полягає в тому, що C не визначає формат типів (тож ви не знаєте, що ваші цілі числа є доповненням двох). Власне кажучи, перші два пункти, які ви згадали, є невірними.


0

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.