Прирост навсегда, и вы получите -2147483648? - PullRequest
5 голосов
/ 01 июня 2011

По умной и сложной причине, которую я на самом деле не хочу объяснять (потому что это включает в себя создание таймера чрезвычайно уродливым и хакерским способом), я написал некоторый код на C # вроде этого:

int i = 0;
while (i >= 0) i++; //Should increment forever
Console.Write(i);

Я ожидал, что программа зависнет навсегда, или произойдет сбой, или что-то в этом роде, но, к моему удивлению, примерно через 20 секунд ожидания я получаю следующее:

-2147483648

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

Ответы [ 9 ]

12 голосов
/ 01 июня 2011

В C # встроенные целые числа представлены последовательностью битовых значений предварительно определенной длины.Для базового типа данных int эта длина составляет 32 бита.Поскольку 32 бита могут представлять только 4 294 967 296 различных возможных значений (так как это 2 ^ 32), очевидно, что ваш код не будет бесконечно зацикливаться с постоянно увеличивающимися значениями.

Поскольку int может содержать как положительные, так и отрицательные числа,знак числа должен быть как-то закодирован.Это сделано с первого бита.Если первый бит равен 1, то число является отрицательным.

Вот значения int, расположенные в числовой строке в шестнадцатеричном и десятичном виде:

 Hexadecimal        Decimal
 -----------    -----------
 0x80000000     -2147483648
 0x80000001     -2147483647
 0x80000002     -2147483646
    ...              ...
 0xFFFFFFFE              -2
 0xFFFFFFFF              -1
 0x00000000               0
 0x00000001               1
 0x00000002               2
     ...             ...
 0x7FFFFFFE      2147483646
 0x7FFFFFFF      2147483647

Как видно изНа этой диаграмме биты, представляющие наименьшее возможное значение, - это то, что вы получили бы, добавив единицу к максимально возможному значению, игнорируя при этом интерпретацию знакового бита.Когда таким образом добавляется число со знаком, оно называется «переполнением целого».Разрешается ли целочисленное переполнение или рассматривается как ошибка, можно настроить с помощью операторов checked и unchecked в C #.По умолчанию этот флажок снят, поэтому ошибок не возникло, но вы получили это сумасшедшее маленькое число в вашей программе.

Это представление называется 2 Complement .

8 голосов
/ 01 июня 2011

Значение переполняет положительный диапазон 32-разрядного целочисленного хранилища и составляет 0xFFFFFFFF, что составляет -2147483648 в десятичном виде. Это означает, что вы переполнены 31-битными целыми числами.

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

2 голосов
/ 01 июня 2011

То, что говорили другие.Если вы хотите что-то, что может продолжаться вечно (и я не буду замечать, почему вам нужно что-то подобное), используйте класс BigInteger в пространстве имен System.Numerics (.NET 4+).Вы можете сделать сравнение с произвольно большим числом.

2 голосов
/ 01 июня 2011

Попробуй так:

int i = 0;
while (i >= 0) 
   checked{ i++; } //Should increment forever
Console.Write(i);

И объясните результаты

2 голосов
/ 01 июня 2011

int - целое число со знаком.Пройдя максимальное значение, оно начинается с минимального значения (большой минус) и движется к 0.

Попробуйте еще раз с uint и посмотрите, что отличается.

2 голосов
/ 01 июня 2011

Вы испытываете Целочисленное переполнение .

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

0 голосов
/ 01 июня 2011

Надеюсь, это не похоже на умный совет, потому что оно хорошо и не должно быть хитрым.

То, что вы просите, это чтобы мы описали то, что является довольно фундаментальным поведением для целочисленных типов данных.

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

Мой совет - возьмите материал для чтения для 1-го курса информатики + оригинальную работу Кнута «Искусство компьютерного программирования», и за ~ 500 долларов у вас будет все, что вам нужно, чтобы стать великим программистом, гораздо дешевле, чем целый Uni. конечно; -)

0 голосов
/ 01 июня 2011

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

Если вам интересно, посмотрите это видео: Парадигмы программирования в 12:25 и далее. Довольно интересно, и вы поймете, почему ваш код ведет себя так, как он делает.

0 голосов
/ 01 июня 2011

Это происходит потому, что когда переменная "i" достигает максимального предела int, следующее значение будет отрицательным.

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