Java가 int를 바이트로 변환 할 때 이상한 행동?


130
int i =132;

byte b =(byte)i; System.out.println(b);

마인드 글링. 왜 출력 -124입니까?

답변:


172

Java에서는 int32 비트입니다. A byte는 8 bits입니다.

자바에있는 대부분의 기본 유형이 서명되고 byte, short, int, 및 long2의 보수로 인코딩됩니다. 합니다 ( char유형은 부호이며, 기호의 개념은 적용되지 않습니다 boolean.)

이 숫자 체계에서 최상위 비트는 숫자의 부호를 지정합니다. 더 많은 비트가 필요한 경우 가장 중요한 비트 ( "MSB")가 새 MSB에 복사됩니다.

그래서 당신은 바이트가있는 경우 255: 11111111 당신은로 표현하려는 int당신이 단순히로 1가 24 번 왼쪽 복사 (32 비트).

음의 2의 보수 수를 읽는 한 가지 방법은 최하위 비트로 시작하여 첫 번째 1을 찾을 때까지 왼쪽으로 이동 한 다음 이후에 모든 비트를 뒤집는 것입니다. 결과 숫자는 해당 숫자의 양수입니다.

예를 들어, = 11111111로 이동합니다 . 이것이 Java가 값으로 표시하는 것입니다.00000001-1

아마도 당신이하고 싶은 것은 부호없는 바이트 값을 아는 것입니다.

가장 중요하지 않은 8 비트를 제외한 모든 것을 삭제하는 비트 마스크를 사용하여이 작업을 수행 할 수 있습니다. (0xff)

그래서:

byte signedByte = -1;
int unsignedByte = signedByte & (0xff);

System.out.println("Signed: " + signedByte + " Unsigned: " + unsignedByte);

인쇄 할 것 : "Signed: -1 Unsigned: 255"

실제로 여기서 무슨 일이 일어나고 있습니까?

우리는 비트 단위 AND를 사용하여 모든 외부 부호 비트 (가장 중요한 8 비트의 왼쪽에 1이 있음)를 마스킹합니다. int가 바이트로 변환 될 때 Java는 가장 왼쪽의 24 비트를 잘라냅니다.

1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101

32 번째 비트는 이제 8 번째 비트 대신 부호 비트이므로 부호 비트를 0으로 설정하면 양수 값으로 Java에서 바이트의 원래 8 비트를 읽습니다.


1
이 주제에 대한 최고의 설명 인 웨인! 나는 2의 보수 표현에서 부호 비트를 오른쪽에 복사하여 비트를 추가 할 수있는 수학 공식화를 찾고 있습니다. 음수를 얻는 방법의 규칙을 생각하면 이해하기 쉽습니다. 즉, 오른쪽에서 왼쪽으로 모든 비트를 고려하고 처음 1이 될 때까지 변경하지 않고 쓰십시오. 그런 다음 후속 비트를 반전시킵니다. 누락 된 비트를 0으로 간주하면 모두 1로 이동한다는 것을 쉽게 이해할 수 있습니다.하지만 더 많은 '수학'설명을 찾고있었습니다.
AgostinoX

무슨 여기 hapenning 것은 signedByte & (0xff)0xff비트 연산이 수행되기 전에 이렇게 signedByte 정수로 추진됩니다, interger의 문자입니다.
Kevin Wheeler

그것은 0xFF가 아니며 예제에서 0x7E입니다!
JohnyTex

89

132자릿수 ( 기본 10 )는 1000_0100비트 ( 기본 2 )이고 Java는 int32 비트로 저장 됩니다.

0000_0000_0000_0000_0000_0000_1000_0100

int-to-byte의 알고리즘은 왼쪽 잘림입니다. 에 대한 알고리즘 System.out.println2의 보수입니다 ( 2의 보수는 가장 왼쪽에있는 비트가 1이면 음의 1의 보수 (비트 반전)에서 1을 뺀 것으로 해석됩니다 ). 따라서 System.out.println(int-to-byte( )):

  • 인터프리터로 (if-leftmost-bit-is-1 [negative (invert-bits (minus-one (] left-truncate ( 0000_0000_0000_0000_0000_0000_1000_0100) [)))]))
  • = interpret-as (if-leftmost-bit-is-1 [negative (invert-bits (빼기 -one (] 1000_0100[)))])
  • = 인터 프리트 그대로 (음 (인버트 비트 (마이너스-원 ( 1000_0100))))
  • = 인터 프리트 그대로 (음 (인버트 비트 ( 1000_0011)))
  • = 그대로 해석 (음수 ( 0111_1100))
  • = 그대로 해석 (음수 (124))
  • =-으로 해석 (-124)
  • = -124 타다 !!!

7
아주 잘 설명
ZAJ

1
이제 십진수 132는 바이트 -124입니다. 반대로 작동하는 방법은 무엇입니까?
Nilesh Deokar

@NileshDeokar, 그 반대는 POLA에 의한 것이기 때문에 (; JLS 5.1.2 참조 ); 출력은 부호 왼쪽 패드 ( 0양수 및 1음수) 와 일치 합니다.
Pacerier

POLA 란 무엇입니까? 에서 inta 로의 변환은 byte손실이 많은 변환입니다 (즉, 정보가 손실 됨). 따라서 원래 int값 으로 다시 변환 할 수있는 방법이 없습니다 .
진실 조정자

23

Java의 바이트는 부호가 있으므로 -2 ^ 7-2 ^ 7-1 범위, 즉 -128-127입니다. 132가 127보다 높으므로 132-256 = -124로 줄 바꿈됩니다. 즉, 기본적으로 256 (2 ^ 8)은 범위에 들어갈 때까지 더하거나 뺍니다.

자세한 내용은 2의 보수 를 읽으십시오 .


16

132는 -128 ~ 127 (Byte.MIN_VALUE ~ Byte.MAX_VALUE) 인 바이트 범위를 벗어납니다. 대신 8 비트 값의 최상위 비트는 부호가있는 것으로 간주되어이 경우 음수임을 나타냅니다. 따라서 숫자는 132-256 = -124입니다.


5

혼란스러운 이론이없는 매우 기계적인 방법은 다음과 같습니다.

  1. 숫자를 이진 표현으로 변환하십시오 (계산기 사용?)
  2. 맨 오른쪽 8 비트 (LSB) 만 복사하고 나머지는 버립니다.
  3. 2 단계의 결과에서 맨 왼쪽 비트가 0이면 계산기를 사용하여 숫자를 10 진수로 변환하십시오. 이것이 당신의 대답입니다.
  4. 그렇지 않으면 (가장 왼쪽 비트가 1 인 경우) 대답은 부정적입니다. 가장 오른쪽의 모든 0과 0이 아닌 첫 번째 비트는 변경하지 마십시오. 나머지는 반대로 1을 0으로 바꾸고 0을 1로 바꿉니다. 그런 다음 계산기를 사용하여 10 진수로 변환하고 음수 부호를 추가하여 값이 음수임을 나타냅니다.

이보다 실용적인 방법은 위의 많은 이론적 답변에 따릅니다. 따라서 여전히 모듈로를 사용한다고 말하는 Java 책을 읽는 사람들은 위에서 설명한 4 단계가 모듈로 작업이 아니기 때문에 분명히 잘못되었습니다.


'모듈로'를 사용한다고 말하는 Java 책은 무엇입니까 ? Java 서적은 물론 46 년 만에 CS 서적을 본 적이 없습니다. '모듈로'는 무엇입니까? Java에는 모듈로 작업이 없습니다. 나머지 연산자 만
Lorne의 후작

더 강하게 인사하십시오. http://iiti.ac.in/people/~tanimad/JavaTheCompleteReference.pdf페이지 59
truthadjustr

4

2의 보수 방정식 :

여기에 이미지 설명을 입력하십시오


Java에서 byte(N = 8) 및 int(N = 32)는 위에 표시된 2의 보수로 표시됩니다.

방정식에서 7 은 음수 byte이지만 에 대해서는 양수입니다 int.

coef:   a7    a6  a5  a4  a3  a2  a1  a0
Binary: 1     0   0   0   0   1   0   0
----------------------------------------------
int:    128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 =  132
byte:  -128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 = -124

2

종종 책에서 모듈로 나누기에 의해 int에서 byte로 캐스트하는 방법에 대한 설명을 찾을 수 있습니다. 이것은 아래에 표시된 것처럼 정확히 정확하지 않습니다. 실제로 가장 왼쪽에있는 비트가 설정되어 숫자를 음수로 지정하면 int 수의 이진 값에서 24 개의 최상위 비트가 무시되고 혼란이 남습니다.

public class castingsample{

public static void main(String args[]){

    int i;
    byte y;
    i = 1024;
    for(i = 1024; i > 0; i-- ){

      y = (byte)i;
      System.out.print(i + " mod 128 = " + i%128 + " also ");
      System.out.println(i + " cast to byte " + " = " + y);

    }

}

}

2
나는 46 년 동안 어떤 책에서도 그것을 본 적이 없다.
Lorne의 후작

2

작동 방식을 시뮬레이트하는 빠른 알고리즘은 다음과 같습니다.

public int toByte(int number) {
    int tmp = number & 0xff
    return (tmp & 0x80) == 0 ? tmp : tmp - 256;
}

어떻게 작동합니까? 에 봐 daixtr 대답. 그의 답변으로 묘사 된 정확한 알고리즘의 구현은 다음과 같습니다.

public static int toByte(int number) {
    int tmp = number & 0xff;
    if ((tmp & 0x80) == 0x80) {
        int bit = 1;
        int mask = 0;
        for(;;) {
            mask |= bit;
            if ((tmp & bit) == 0) {
                bit <<=1;
                continue;
            }
            int left = tmp & (~mask);
            int right = tmp & mask;
            left = ~left;
            left &= (~mask);
            tmp = left | right;
            tmp = -(tmp & 0xff);
            break;
        }
    }
    return tmp;
}

1

이것이 어떻게 작동하는지와 같이 이것을 수학적으로 이해하려면

따라서 기본적으로 b / w -128 ~ 127의 숫자는 소수점 이하의 숫자와 동일하게 작성됩니다 (숫자-256).

예. 132, 대답은 132-256 =-124입니다. 즉

256 + 숫자 256 + (-124)의 답은 132입니다

다른 예시

double a = 295.04;
int b = 300;
byte c = (byte) a;
byte d = (byte) b; System.out.println(c + " " + d);

출력은 39 44입니다

(295-256) (300-256)

참고 : 소수점 이하의 숫자는 고려하지 않습니다.


0

개념적으로, -128에서 +127 사이의 범위가 될 때까지 256의 반복 된 뺄셈이 숫자로 이루어집니다. 따라서 귀하의 경우 132로 시작한 다음 한 단계에서 -124로 끝납니다.

계산 상 이것은 원래 숫자에서 8 개의 최하위 비트를 추출하는 것에 해당합니다. (그리고이 8 개의 최상위 비트는 부호 비트가됩니다.)

다른 언어에서는이 동작이 정의되어 있지 않습니다 (예 : C 및 C ++).


명확하게하기 위해, 당신이 얻을 결과는 동일 처럼 반복 뺄셈이 완료되었다. 실제로 JVM은 실제로이 방법으로 수행하지 않습니다. (끔찍하게 비효율적입니다!)
Stephen C

과연. 두 번째 단락이 JVM이 실제로 어떻게 수행하는지 다루기를 바랍니다. 그러나 나는 나의 언어를 조금 어지럽히고있다.
Bathsheba

1
예. "본질적으로" "개념적으로"로의 변화는 큰 차이를 만듭니다!
Stephen C

-1
 N is input number
case 1: 0<=N<=127  answer=N;
case 2: 128<=N<=256 answer=N-256 
case 3: N>256   
        temp1=N/256;
        temp2=N-temp*256;
        if temp2<=127   then answer=temp2;
        else if temp2>=128  then answer=temp2-256;
case 4: negative  number input
        do same procedure.just change the sign of the solution           

정답은 나눗셈과 나머지가 아닌 비트 마스킹에 의해 도달합니다.
Lorne의 후작
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.