int i =132;
byte b =(byte)i; System.out.println(b);
Mindboggling. Почему на выходе -124
?
В Java int
- 32 бита. А byte
равно 8 bits
.
Большинство примитивных типов в Java подписаны, и byte
, short
, int
, и long
кодируются в виде дополнения до двух. ( char
Тип беззнаковый, и понятие знака не применимо к boolean
.)
В этой числовой схеме старший бит определяет знак числа. Если требуется больше бит, старший бит («MSB») просто копируется в новый MSB.
Итак, если у вас есть byte 255
: 11111111
и вы хотите представить его как int
(32 бита), вы просто копируете 1 влево 24 раза.
Теперь один из способов прочитать отрицательное число в дополнительном коде до двух - начать с младшего значащего бита, двигаться влево, пока не найдете первую единицу, а затем инвертировать каждый бит. Полученное число является положительной версией этого числа.
Например: 11111111
идет к 00000001
= -1
. Это то, что Java будет отображать как значение.
Вы, вероятно, захотите узнать беззнаковое значение байта.
Вы можете сделать это с помощью битовой маски, которая удаляет все, кроме младших 8 бит. (0xff)
Так:
byte signedByte = -1;
int unsignedByte = signedByte & (0xff);
System.out.println("Signed: " + signedByte + " Unsigned: " + unsignedByte);
Распечатал бы: "Signed: -1 Unsigned: 255"
Что на самом деле здесь происходит?
Мы используем побитовое И, чтобы замаскировать все посторонние биты знака (1 слева от младших 8 бит). Когда int преобразуется в байт, Java отрезает самые левые 24 бита.
1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101
Поскольку 32-й бит теперь является битом знака вместо 8-го (и мы установили бит знака в 0, который является положительным), исходные 8 битов из байта считываются Java как положительное значение.
signedByte & (0xff)
происходит, так0xff
это то, что это межчисленный литерал, таким образом, signedByte становится целым перед выполнением побитовой операции.132
в цифрах ( база 10 ) -1000_0100
в битах ( база 2 ), а в Java хранитсяint
32 бита:Алгоритм преобразования целых чисел в байты - усечение слева; Алгоритм для
System.out.println
является дополнением до двух ( дополнение до двух - если крайний левый бит имеет значение1
, интерпретируется как отрицательное дополнение до единицы (инвертировать биты) минус один.); Таким образомSystem.out.println(int-to-byte(
))
:0000_0000_0000_0000_0000_0000_1000_0100
) [)))])1000_0100
[)))])1000_0100
))))1000_0011
)))0111_1100
))источник
0
для положительного и1
отрицательного).int
в abyte
- это преобразование с потерями (т. Е. Информация теряется). Следовательно, нет возможности преобразовать его обратно в исходноеint
значение.байт в Java подписан, поэтому он имеет диапазон от -2 ^ 7 до 2 ^ 7-1, т. е. от -128 до 127. Поскольку 132 больше 127, вы в конечном итоге оборачиваетесь до 132-256 = -124. То есть по существу 256 (2 ^ 8) добавляется или вычитается, пока не попадет в диапазон.
Для получения дополнительной информации вы можете прочитать о дополнении до двух .
источник
132 находится вне диапазона байта, который составляет от -128 до 127 (от Byte.MIN_VALUE до Byte.MAX_VALUE). Вместо этого верхний бит 8-битного значения обрабатывается как знаковый, что указывает на то, что в данном случае оно отрицательное. Таким образом, число 132 - 256 = -124.
источник
вот очень механический метод без отвлекающих теорий:
Этот более практичный метод соответствует приведенным выше теоретическим ответам. Итак, те, кто все еще читает книги по Java, в которых говорится об использовании по модулю, это определенно неверно, поскольку 4 шага, которые я описал выше, определенно не являются операцией по модулю.
источник
http://iiti.ac.in/people/~tanimad/JavaTheCompleteReference.pdf
страница 59Уравнение с дополнением до двух:
В Java
byte
(N = 8) иint
(N = 32) представлены 2s-дополнением, показанным выше.Из уравнения 7 отрицательно для,
byte
но положительно дляint
.источник
часто в книгах вы найдете объяснение преобразования типа int в byte как выполнения модульного деления. это не совсем правильно, как показано ниже, что на самом деле происходит: 24 старших бита из двоичного значения числа int отбрасываются, оставляя путаницу, если установлен оставшийся крайний левый бит, который обозначает число как отрицательное
источник
Быстрый алгоритм, имитирующий его работу, следующий:
Как это работает? Посмотрите на ответ daixtr . Реализация точного алгоритма, описанного в его ответе, следующая:
источник
Если вы хотите понять это математически, например, как это работает
поэтому в основном числа ч / б от -128 до 127 будут записаны так же, как их десятичное значение, выше его (ваше число - 256).
например. 132, ответ будет 132 - 256 = - 124 т.е.
256 + ваш ответ в числе 256 + (-124) 132
Другой пример
Выход будет 39 44
(295 - 256) (300 - 256)
ПРИМЕЧАНИЕ: он не будет рассматривать числа после десятичной дроби.
источник
По сути, для вашего числа выполняются повторные вычитания 256, пока оно не окажется в диапазоне от -128 до +127. Итак, в вашем случае вы начинаете со 132, а затем заканчиваете -124 за один шаг.
С вычислительной точки зрения это соответствует извлечению 8 младших битов из исходного числа. (И обратите внимание, что старший бит из этих 8 становится битом знака.)
Обратите внимание, что в других языках это поведение не определено (например, C и C ++).
источник
источник