Programing

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

lottogame 2020. 7. 3. 18:42
반응형

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


int i =132;

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

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


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 비트를 읽습니다.


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 타다 !!!

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

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


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


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

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

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


2의 보수 방정식 :

enter image description here


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

often in books you will find the explanation of casting from int to byte as being performed by modulus division. this is not strictly correct as shown below what actually happens is the 24 most significant bits from the binary value of the int number are discarded leaving confusion if the remaining leftmost bit is set which designates the number as negative

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);

    }

}

}

A quick algorithm that simulates the way that it work is the following:

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

How this work ? Look to daixtr answer. A implementation of exact algorithm discribed in his answer is the following:

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;
}

Conceptually, repeated subtractions of 256 are made to your number, until it is in the range -128 to +127. So in your case, you start with 132, then end up with -124 in one step.

Computationally, this corresponds to extracting the 8 least significant bits from your original number. (And note that the most significant bit of these 8 becomes the sign bit.)

Note that in other languages this behaviour is not defined (e.g. C and C++).


If you want to understand this mathematically, like how this works

so basically numbers b/w -128 to 127 will be written same as their decimal value, above that its (your number - 256).

eg. 132, the answer will be 132 - 256 = - 124 i.e.

256 + your answer in the number 256 + (-124) is 132

Another Example

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

the Output will be 39 44

(295 - 256) (300 - 256)

NOTE: it won't consider numbers after the decimal.


 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           

참고URL : https://stackoverflow.com/questions/842817/odd-behavior-when-java-converts-int-to-byte

반응형