JavaRush/Java блог/Random/Приведение примитивных типов. Приведение типа int к типу ...
Георгий
22 уровень

Приведение примитивных типов. Приведение типа int к типу short и byte

Статья из группы Random
участников
Приведение примитивных типов. Приведение типа int к типу short и byte - 1Почему, если привести какие-нибудь значения типа int к типу short или byte, результаты бывают неожиданными? Давайте разбираться!
int i = 450;
byte b = (byte)i;
System.out.println(b);
Результат на экране:

-62
Неожиданно, но этому есть логическое объяснение, более того, это действие можно сделать собственноручно. Для этого, нам нужно перевести 450 из десятичной системы в двоичную:

450/2.    0
225/2.    1
112/2.    0
56/2.     0
28/2.     0
14/2.     0
7/2.      1
3/2.      1
1/2.      1
В правый столбик от числа мы записываем его остаток от деления на 2, а под самим числом пишем результат деления нашего числа на два, если остаток 0. Если остаток 1, то ниже записываем целую часть от деления на два. (Онлайн калькулятор с объяснением вычислений). В итоге, мы получаем, что в двоичной системе счисления 450 = 11100 0010. Любое число типа int занимает 4 байта или 32 бита, где каждый бит - это 0 или 1. В нашем случае заняты только 9 битов, и в принципе наш int i = 450 в двоичной системе выглядит так:

0000_0000_0000_0000_0000_0001_1100_0010
Мы хотим записать нашу переменную в переменную типа byte, но число типа byte занимает 1 байт (следует из названия этого типа) или 8 бит. Поэтому лишние биты слева просто отбрасываются, и в итоге мы получаем:

1100 0010
Диапазон значений типа byte: -128 до 127. Каждое число занимает 8 бит и у каждого числа крайний левый бит - знаковый бит(sign bit). У всех положительных чисел он равен 0, у всех отрицательных он равен 1. Спешить переводить наш результат, полученный выше, в 10-ную систему не нужно, т.к. мы получили дополнительный код искомого числа, а не прямой. Крайний бит слева получился равен 1, следовательно число у нас отрицательное, а у отрицательных чисел прямой и обратный код не совпадает, в отличие от положительных. Если бы знаковый бит был равен 0, то мы могли бы сразу перевести число в десятичную систему счисления и получить: 66. Но знаковый бит отрицательный, поэтому сначала дополнительный код нужно перевести в прямой и добавить к ответу знак минус. Для наглядности и тренировки, сначала попробуем получить дополнительный код какого-нибудь числа, например -15. Для этого в прямом коде его положительного представления (числа 15) нужно поменять все 0 на 1 и наоборот (получить обратный код, также называют инверсный), а затем добавить к результату единицу. В десятичной системе 15 = 0000 1111; Обратный код (меняем все 0 на 1 и наоборот) = 1111 0000; Дополнительный код(прибавляем единицу):

1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 1
1 1 1 1 0 0 0 1
Дополнительный код числа -15: 1111 0001; Отлично.Теперь, по аналогии с примером выше, нам нужно перевести уже наш дополнительный код в прямой, напомню, он равен 1100 0010.
  1. Отнимаем единицу и получаем обратный код. Удобно делать так, записать дополнительный код в ответ и смотреть, к чему нужно прибавить единицу, чтобы получить такой дополнительный код. Начинаем с крайнего правого разряда и смотрим: к чему нужно прибавить 1 чтобы получить 0? К 1, получим 10, 0 уходит в ответ, а единичка на следующий разряд. Далее, что нужно прибавить к 0, чтобы получить один. Единицу, но так как мы с предыдущего разряда имеем единичку, то в ответ пишем 0. Далее, чтобы получить 0, что нужно прибавить к 0? Конечно, 0. Так ещё 4 раза. И остались последние 2 разряда, где к 0 надо что-то прибавить, чтобы получить 1. Конечно, в обоих случаях нужно прибавить 1. Итого:

    
    1 1 0 0 0 0 0 1
    0 0 0 0 0 0 0 1
    1 1 0 0 0 0 1 0
    
  2. Самое сложное позади! Мы получили инверсный(обратный) код и нам осталось получить прямой. Инвертируем все 0 на 1 и наоборот:

    1100 0001 - инверсный код;

    0011 1110 - прямой код нашего числа, точнее его положительного представления;

  3. Переводим в десятичную систему счисления (Онлайн калькулятор с объяснением вычислений):

    0011 1110 = 0∙2^7+0∙2^6+1∙2^5+1∙2^4+1∙2^3+1∙2^2+1∙2^1+0∙2^0 = 0+0+32+16+8+4+2+0 = 62;

    Осталось только добавить к числу минус и наш ответ: -62.

Таким же образом преобразуются числа типа short к типу int:
int i = 10_000_000;
short s = (short)i;
System.out.println(s); // -27008
  1. 10.000.000 в 10-ной системе счисления = 0000 0000 1001 1000 1001 0110 1000 0000 в 2-ной.

    В Java число типа int занимает 4 байта, а short - 2 байта, или 16 бит, поэтому отсекаем слева до 16 цифр:

  2. 1001 0110 1000 0000. Крайний левый бит(старший бит, он же знаковый бит) получился равен 1. Значит перед нами дополнительный код отрицательного числа, поэтому переходим к следующему пункту.
  3. Переводим в обратный код:

    
    1 0 0 1 0 1 1 0 0 1 1 1 1 1 1 1
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
    1 0 0 1 0 1 1 0 1 0 0 0 0 0 0 0
    

    Обратный код: 1001 0110 0111 1111;

  4. Инвертируем и получаем прямой код: 0110 1001 1000 0000.

  5. Переводим в двоичную систему счисления и получаем положительное представление нашего числа:

    1∙2^14+1∙2^13+1∙2^11+1∙2^8+1∙2^7 = 16384+8192+2048+256+128 = 27008.
  6. Добавляем минус и получаем ответ: -27008

Приведение примитивных типов. Приведение типа int к типу short и byte - 2Ссылка на онлайн-калькулятор прямого, обратного и дополнительного кода. Также на этом сайте под калькулятором есть немного теории об обратном и дополнительном коде.
Комментарии (8)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Daria_Grin
Уровень 19
3 мая 2023, 13:16
Это единственная статья, которую я нашла в инете, где этот вопрос понятно объясняется! Спасибо! Но зачем нужен прямой и обратный коды? Зачем так усложнять? Почему нельзя пользоваться только прямым кодом?
Очень крутая статья! Спасибо!
Ойбек Нурматов
Уровень 20
20 июня 2020, 02:32
отлично мне очень понравилось это статью, полезно
dolcom20
Уровень 5
2 июня 2020, 07:47
Спасибо за полезную статью! Т.е. если в старшем бите единица, то перед нами дополнительный код отрицательного числа => вычитаем единицу и получаем обратный код, затем инвертируем обратный код, чтобы получить прямой, прямой переводим в десятичную сс и добавляем к нему минус впереди. Гениально, только сложно! 😃
Георгий Java Developer в Deutsche Telekom IT
4 июня 2020, 02:23
Спасибо за отзыв! Мы в любом случае получаем дополнительный код, но у положительных чисел он равен прямому, поэтому можно сразу переводить в десятичную. Если мы видим единицу в старшем бите, то это значит, что число отрицательное, и код нужно переводить. По идее, мы переводим для того, чтобы получить положительное представление нашего отрицательного числа, перевести его в десятичку и добавить к ответу знак минуса. И для этого делаются эти 2 операции - вычитание единицы и инверсия.
26 апреля 2020, 13:12
"Почему, если привести какие-нибудь значения типа int к типу short или byte, результаты бывают неожиданными?" Исключительно для тех, кто не знает сути приведения.
Hanna Moruga Chief editor @ JavaRush
8 мая 2020, 15:06
Для тех, кто пока еще недостаточно вник в суть, статья и написана, судя по всему)
Юрий
Уровень 31
23 апреля 2020, 09:47
Хорошая статья!