Подтвердить что ты не робот

Превращение int в короткий дает неожиданные результаты

Я немного смущен информацией о потерях в числовых типах на С#.

Когда я делаю это:

int x = 32780;
short y = (short)x;

У меня есть результат: -32756 для y, а не ожидаемый 32767. Почему? Как это рассчитывается?

Диапазон коротких: -32768 до 32767 Диапазон значений int: -2,147,483,648 до 2,147,483,647

4b9b3361

Ответ 1

Кажется, вы ожидаете эффекта "округления", а не того, что на самом деле происходит, что является поразрядной повторной интерпретацией данных.

В двоичном формате x равен 00000000000000001000000000001100, который представляет собой 32-разрядное число с шестнадцати значащими битами. A short - это 16-разрядное целое число со знаком, которое представлено с помощью двухкомпонентной нотации.

При преобразовании последние 16 бит вашего x копируются в y, давая 1000000000001100. Важно отметить, что первая цифра равна 1. В двухзадачной нотации это -32756. Ваш номер не округлен - его читали, как будто он был 16-битным.

Ответ 2

Прочитайте Дэн ответ за "истинную" причину этого, но достаточно будет подумать об этом так: когда число переполняет свой максимум, оно возвращается к минимуму. Итак, 32780 - 32767 = 13 и -32768 (which is one of the 13) + 12 (the other 12) = -32756

Ответ 3

Можно сказать, что среда выполнения добавляет или вычитает 65536 столько раз, сколько необходимо для получения номера в пределах диапазона типа short (System.Int16).

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

Для этого рассмотрим тип short как целые числа по модулю 65536, также записанные как ℤ/65536ℤ. Каждый член класса ℤ/65536ℤ является классом конгруэнтности, т.е. Множеством чисел, имеющих одинаковый остаток при делении на 65536. Теперь каждый класс сравнения имеет бесконечность разных членов ( "представителей" ). Если вы выберете один, вы получите все остальные, повторяя добавление или вычитание 65536.

С типом данных short мы выбираем единственный представитель в интервале -32768 через +32767. Тогда ushort - это то же самое, только мы выбираем представителя в 0 через 65535.

Теперь прохладно о ℤ/65536ℤ состоит в том, что он образует ring, в котором мы имеем дополнение, вычитание и умножение (но не). И фактически, в unchecked контексте, с short x,y;, операции С#

(short)(x + y)
(short)(x - y)
(short)(x * y)

точно соответствуют арифметике в ℤ/65536ℤ. (Здесь мы должны вернуться к short, потому что технически С# определяет операторы только для int, uint, long и ulong.)

Таким же образом, sbyte и byte можно рассматривать как кольцо ℤ/256ℤ, int и uint как ℤ/4294967296ℤ и long и ulong как ℤ/18446744073709551615ℤ.

Заметим, однако, что, поскольку эти модули не являются простыми числами, деление в кольце невозможно. Например, no int X удовлетворяет

unchecked( 10 * X == 35 )   // integers Int32

и, следовательно, не ясно, что должен быть 35/10. С другой стороны, два X удовлетворяют

unchecked( 10 * X == 36 )   // integers Int32

но какой из них должен быть 36/10?

Однако ровно один int X делает

unchecked( 11 * X == 35 )   // integers Int32

верно. Нам повезло, потому что 11 относительно просто с 4294967296. Решение X равно 1952257865 (проверьте для себя), поэтому фактор 35/11 в некотором смысле имеет номер X.

Заключение: целые операции +, - и * С# можно интерпретировать как просто кольцевые операции в ℤ/nℤ. Но операция / никак не связана с кольцом!

Ответ 4

Когда вы используете x для короткого замыкания, вы получите переполнение (то есть значение, которому назначено больше, чем оно могло бы обрабатывать), и ваше значение будет представлено в виде мысли, что оно начнется снова, начиная с значения min. Как вы сказали, короткое максимальное значение равно 32767, поэтому ваше новое значение будет: -32768 + (32780 - 32768) = -32756

В зависимости от языка программирования (и, возможно, вашего компилятора) то, что вы пытаетесь сделать, может привести к исключению или нет. Кажется, в С# это не так.

Ответ 5

Есть переполнение. Если вы хотите, чтобы число было ограничено максимальным значением, вы можете обойти это, сравнив целое число с short.MaxValue:

short y;
if (x > short.MaxValue) {
    y = short.MaxValue;
} else if (x < short.MinValue) {
    y = short.MinValue;
} else {
    y = (short)x;
}