자바에서 레프트 시프트 연산 주의할 점 (-1 << 32의 값은?)

ino5·2021년 4월 27일
0
post-thumbnail

소개


자바에서 비트 연산(레프트 시프트;left shift)을 사용하던 도중 생각한 값과 다르게 나와서 원인을 찾고 정리해보았습니다.



-1<<32의 값은?


int형이라고 했을 때 1<<1-1<<1을 비트로 표현하면

11111111111111111111111111111111(2)11111111111111111111111111111111_{(2)}

입니다. (11이 32개)

왼쪽 시프트 연산자인 <<<<은 제일 오른쪽에 00을 밀어넣어, 제일 왼쪽에 있는 숫자는 밀어내는 것과 같습니다.

1<<1-1<<1 이라면 00을 한번 밀어넣는 것이 되어

11111111111111111111111111111110(2)11111111111111111111111111111110_{(2)}

이 됩니다.(11이 31개, 가장 오른쪽에 00이 1개)

1<<32-1<<32 는 위의 과정을 32번하는 것으로 결국

00000000000000000000000000000000(2)00000000000000000000000000000000_{(2)}

이 됩니다.(11이 31개, 가장 오른쪽에 00이 1개)
즉, 1<<32-1<<3200이 됩니다.

c언어에서도 테스트해보면 1<<32-1<<3200이 나옵니다.



자바에서의 -1<<32


자바에서는 1<<32-1<<32 를 하면 00이 아닌 다른 값이 나옵니다.

00이 아닌 1-1이 나오게 됩니다. 왜 그런 것일까요?




아래 링크에 이에 대한 설명이 나와 있습니다.(15.19. Shift Operators)
https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.19

If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.


Left shift연산(<<<<)의 오른쪽 피연산자의 값이 00에서 3131까지 유효하다고 합니다. 오른쪽 피연산자의 값이 만약 이 범위를 벗어난다면 최하위 비트 다섯 개만 읽는다고 합니다.

그래서 1<<32-1<<32 를 하게되면 여기서 3232100000(2)100000_{(2)} 이므로 앞의 다섯 개의 비트만 읽어 00으로 보고 연산하게 됩니다. 즉, 1<<0-1<<0 의 값을 내어 -1이 나오게 되는 것입니다.


그래서 1<<32-1<<32(1<<31)<<1(-1<<31)<<1 와 같이 표현하면 올바른 값을 얻을 수 있습니다.

profile
궁금한 것을 찾아보거나 문제를 해결한 과정을 날 것의 글로 작성하였습니다.

1개의 댓글

comment-user-thumbnail
2023년 10월 29일

저도 원 형식으로 비트가 넘어가는게아니라 끝단에서 버리는거라고 알고있는데 32비트부턴 이상하게 되더라니 이런 원리였군요 근데 c언어에서는 잘 구현해놨는데 왜 자바는 저렇게 구현했을까요?

답글 달기