비트 연산 문서의 구현 코드다.
// 실행: docker run --rm -v "$PWD":/w -w /w eclipse-temurin:21-jdk java 05_java-bitwise_impl.java
// 비트 연산 문서의 값을 확인한다.
class BitwiseImpl {
static void check(boolean ok, String what) {
if (!ok) throw new AssertionError(what);
}
static String bits8(int v) {
String s = Integer.toBinaryString(v & 0xFF);
return "0".repeat(8 - s.length()) + s;
}
public static void main(String[] args) {
// 1. 45와 25의 비트
check(bits8(45).equals("00101101"), "45 = 00101101");
check(bits8(25).equals("00011001"), "25 = 00011001");
check((45 & 25) == 9 && bits8(45 & 25).equals("00001001"), "45 & 25 = 9");
check((45 | 25) == 61 && bits8(45 | 25).equals("00111101"), "45 | 25 = 61");
check((45 ^ 25) == 52 && bits8(45 ^ 25).equals("00110100"), "45 ^ 25 = 52");
check(~45 == -46 && bits8(~45).equals("11010010"), "~45 = -46");
// ~x = -x - 1
for (int x = -1000; x <= 1000; x++) {
check(~x == -x - 1, "~x = -x - 1");
check((x ^ x) == 0 && (x ^ 0) == x, "x ^ x = 0, x ^ 0 = x");
check(((x ^ 77) ^ 77) == x, "같은 값으로 두 번 XOR하면 돌아온다");
}
// 2. 시프트
check(1 << 3 == 8, "1 << 3 = 8");
check(5 << 2 == 20, "5 << 2 = 20");
check(20 >> 2 == 5, "20 >> 2 = 5");
check(-8 >> 1 == -4, "-8 >> 1 = -4");
check(-8 >>> 1 == 2147483644, "-8 >>> 1 = 2147483644");
check(-1 >> 31 == -1 && -1 >>> 31 == 1, "-1 >> 31, -1 >>> 31");
check(8 >>> 1 == 4, "양수는 >>와 >>>가 같다");
// 음수 홀수에서 >> 는 나눗셈과 다르다
check(-7 >> 1 == -4, "-7 >> 1 = -4");
check(-7 / 2 == -3, "-7 / 2 = -3");
check(Math.floorDiv(-7, 2) == -4, "floorDiv(-7, 2) = -4");
for (int x = -200; x <= 200; x++) {
for (int s = 0; s < 8; s++) {
check(x << s == x * (1 << s), "x << s = x * 2^s");
check(x >> s == Math.floorDiv(x, 1 << s), "x >> s = 내림 나눗셈");
}
}
// 왼쪽 시프트도 넘친다
check(1 << 31 == Integer.MIN_VALUE, "1 << 31 = 최솟값");
check(1 << 32 == 1, "int는 시프트 수의 아래 5비트만 쓴다: 1 << 32 = 1");
check(1L << 32 == 4294967296L, "long이면 1L << 32 = 2^32");
check(1 << 33 == 2, "1 << 33 = 2");
// 3. byte, short는 int로 바뀐 뒤 계산한다
byte b = (byte) 0b11110000; // -16
check(b == -16, "byte 11110000 = -16");
check(b >>> 4 == 268435455, "-16 >>> 4 (int로 계산) = 268435455");
check((b & 0xFF) >>> 4 == 15, "(b & 0xFF) >>> 4 = 15");
check((b & 0xFF) == 240, "b & 0xFF = 240");
// 4. 쓰임: 짝홀, 특정 비트 켜기·끄기·확인
check((45 & 1) == 1 && (24 & 1) == 0, "마지막 비트로 짝홀 판별");
check((-7 & 1) == 1, "음수도 된다");
int flags = 0;
final int READ = 1 << 0, WRITE = 1 << 1, EXEC = 1 << 2;
flags |= READ;
flags |= EXEC;
check(flags == 5, "READ | EXEC = 5");
check((flags & WRITE) == 0 && (flags & EXEC) != 0, "비트 확인");
flags &= ~READ;
check(flags == 4, "READ 끄기");
flags ^= WRITE;
check(flags == 6, "WRITE 뒤집기");
// 색 0xRRGGBB에서 초록 꺼내기
int color = 0x3B82C4;
check(((color >> 8) & 0xFF) == 0x82, "초록 성분 0x82 = 130");
check(((color >> 16) & 0xFF) == 59 && (color & 0xFF) == 196, "빨강 59, 파랑 196");
// 5. 카드
check((12 & 10) == 8 && (12 | 10) == 14 && (12 ^ 10) == 6 && ~12 == -13, "12와 10");
check((6 << 2 | 3) == 27, "6 << 2 | 3 = 27");
check((1 << 4) - 1 == 15, "(1 << 4) - 1 = 15");
check(-16 >> 2 == -4 && -16 >>> 28 == 15, "-16 >> 2 = -4, -16 >>> 28 = 15");
// 6. boolean에 쓰는 &, |, ^ 는 논리 연산이다
check((true & false) == false && (true | false) == true && (true ^ true) == false, "boolean &, |, ^");
System.out.println("ALL CHECKS PASSED");
}
}