Целочисленная проблема переполнения - PullRequest
0 голосов
/ 20 августа 2009

Пожалуйста, объясните следующий параграф.

"Следующий вопрос - можем ли мы присвоить определенное значение переменной без потери точности. Недостаточно, если мы просто проверяем переполнение при сложении или вычитании, потому что кто-то может добавить от 1 до -5 и присвоить результат to unsigned int. Тогда фактическое добавление не переполняется, но результат все еще не соответствует. "

когда я добавляю 1 к -5, я не вижу причин для беспокойства. Ответ таков, как и должно быть -4. так в чем же проблема того, что результат не подходит? Вы можете найти полную статью здесь, через которую я собирался:

http://www.fefe.de/intof.html

Ответы [ 8 ]

5 голосов
/ 20 августа 2009

Попробуйте присвоить его неподписанному int, а не int.

Ключ unsigned int является ключевым - по умолчанию тип данных int будет содержать отрицательные и положительные числа; однако беззнаковые целые числа всегда положительны. Они предоставляют эту опцию, потому что уинты могут технически содержать большие положительные значения, чем обычные целые числа со знаком, потому что им не нужно использовать бит, чтобы отслеживать, является ли он отрицательным или положительным.

Пожалуйста, смотрите:

Целые числа без знака и без знака

5 голосов
/ 20 августа 2009

Двоичное представление -4 в 32-битном слове выглядит следующим образом (шестнадцатеричное представление)

0xfffffffc

Когда интерпретируется как целое число без знака , этот битовый шаблон представляет число 2 ** 32-4 или 18446744073709551612. Я не уверен, что назвал бы это явление "переполнением ", но распространенная ошибка - присвоить маленькое отрицательное целое число переменной типа без знака и получить действительно большое положительное целое число.

Этот трюк фактически используется для проверки границ: если у вас есть целое число со знаком i и вы хотите узнать, находится ли оно в диапазоне 0 <= i <n, вы можете проверить </p>

if ((unsigned)i < n) { ... }

, который дает вам ответ, используя одно сравнение вместо двух. Приведение к неподписанному не имеет затрат времени выполнения; он просто указывает компилятору генерировать сравнение без знака вместо сравнения со знаком.

2 голосов
/ 20 августа 2009

Проблема в том, что размеры хранилища, такие как unsigned int, могут вместить только столько. С 1 и -5 это не имеет значения, но с 1 и -500000000 вы можете получить запутанный результат. Кроме того, unsigned хранилище будет интерпретировать все, что хранится в нем, как положительное, поэтому вы не можете поместить отрицательное значение в переменную unsigned.

Две важные вещи, на которые стоит обратить внимание:
1. Переполнение самой операции: 1 + -500000000
2. Проблемы в кастинге: (unsigned int)(1 + -500)

2 голосов
/ 20 августа 2009

Проблема в том, что вы храните -4 в без знака int. Целые числа без знака могут содержать только нулевые и положительные значения. Если вы назначите -4 для одного, вы на самом деле получите очень большое положительное число (фактическое значение зависит от того, насколько широко используется int).

0 голосов
/ 21 августа 2009

Вы должны помнить, что в основном вы работаете с битами. Таким образом, вы можете присвоить значение -4 целому числу без знака, и это поместит серию битов в эту область памяти. Эти биты могут быть интерпретированы как -4 при определенных обстоятельствах . Одним из таких обстоятельств является очевидное: вы сказали компилятору / системе, что биты в этой ячейке памяти должны интерпретироваться как число с комплиментом в виде двоих. Поэтому, если вы выполните printf ("% s", i) prtinf выполняет свою магию и преобразует число комплиментов двух в величину и знак. Величина будет 4, а знак будет отрицательным, поэтому он отображает «-4».

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

0 голосов
/ 20 августа 2009

Код:

signed int first, second;
unsigned int result;

first = obtain(); // happens to be 1
second = obtain(); // happens to be -5
result = first + second; // unexpected result here - very large number - and it's too late to check that there's a problem

Скажем, вы получили эти значения с клавиатуры. Перед сложением нужно проверить, что результат может быть представлен в unsigned int. Об этом говорится в статье.

0 голосов
/ 20 августа 2009

Переменные без знака, как и unsigned int, не могут содержать отрицательные значения. Таким образом, присвоение 1 - 5 неподписанному int не даст вам -4. Я не уверен, что это даст вам, вероятно, это зависит от компилятора.

0 голосов
/ 20 августа 2009

По определению число -4 не может быть представлено в unsigned int. -4 - целое число со знаком. То же самое касается любого отрицательного числа.

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

В дополнении к двум, -4 представляется как 0xfffffffc. Когда 0xfffffffc представлен как unsigned int, вы получите число 4,294,967,292.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...