주간 devtips 3

junto·2024년 6월 16일

devtips

목록 보기
3/5

자바에서 >>> 연산으로 overflow처리

java binarySearch 구현 부분을 보는데, low와 high 더하고 비트 연산을 통해 처리한 부분이 신기해서 알아보게 되었다. mid 값을 int로 담아도 되는 걸까?

// java의 binarySearch 구현 부분
private static int binarySearch0(long[] a, int fromIndex, int toIndex,
                                     long key) {
    int low = fromIndex;
    int high = toIndex - 1;
    while (low <= high) {
            int mid = (low + high) >>> 1;
            ...
    }
}

왜 아래 코드는 오버플로우 되지 않을까?

int a1 = 1_500_000_000;
int b1 = 1_500_000_000;
System.out.println((a1 + b1) >>> 1); // 1_500_000_000

자바 비트 이동 연산

1. <<

  • 지정된 비트 수만큼 비트를 왼쪽으로 이동시킨다. 오른쪽 빈자리는 0으로 채운다.

2. >>

  • 지정된 비트 수만큼 비트를 오른쪽으로 이동시킨다. 왼쪽 빈자리는 부호 비트로 채운다.

3. >>>

  • 지정된 비트 수만큼 비트를 오른쪽으로 이동시킨다. 왼쪽 빈자리는 0으로 채운다. 즉, 음수가 양수가 될 수 있다.

컴퓨터가 음수를 표현하는 방법 (2의 보수)

  • 컴퓨터는 int의 32비트 중 절반은 음수를 위해 할당한다. 즉 앞자리가 1로 시작한다. 컴퓨터는 덧셈으로 음수를 표현하기 위한 방법으로 2의 보수를 사용한다.
  • 2의 보수란 기존 수 x에 대하여 모든 비트를 반전시키고, +1을 한 값을 나타낸다.
  • 어떤 수 x와 x의 2의 보수를 더하면 0이 되는 데, 이는 최상위 비트를 초과한 자리올림이 발생하고, 나머지는 0으로 채워져 최상위 비트를 초과한 비트에 대해선 저장할 수 없기에 버림이 발생한다. 따라서 0이 되어 자연스럽게 2의 보수는 음수를 나타내는 것이다.
// 4비트 시스템에서 예를 들어보자.
0010의 보수는 1110이다.
둘을 더하면, 10000이지만, 초과한 비트에 대해선 버린다. 0이 된다.
1110(-2)에서 양수를 구하려면, 뒤집고 더하면 0010(2)가 된다.

오버플로우 되지 않는 이유

0101_1001_0110_1000_0010_1111_0000_0000 // 1_500_000_000;
+
0101_1001_0110_1000_0010_1111_0000_0000 // 1_500_000_000;

= 
1011_0010_1101_0000_0101_1110_0000_0000 // 여기에서 >>> 1 연산
0101_1001_0110_1000_0010_1111_0000_0000 // 즉, 처음과 같아진다.

Java에서 C++ pair 사용하기

  • 알고리즘 문제를 풀 때 Java에서 C++에서 pair나 tuple 같은 자료구조를 지원하지 않아서 간단한 데이터를 담기가 불편했다. 물론, 클래스를 새로 선언하면 되지만 코드양이 많아지기 때문이다.
  • 아래와 같이 int[] 배열로 사용할 수 있다.
jq.add(new int[]{i, j});
int[] cur = fq.poll();
int ny = cur[0] + dy[dir];
int nx = cur[1] + dx[dir];

Mysql 집계함수 기본 동작

select sum(o1_0.total_all_price),count(o1_0.order_id) from orders o1_0
where o1_0.order_date between '2024-06-10T16:24:20.005+0900' and '2024-06-10T17:24:20.005+0900' 
and o1_0.order_status in ('ORDER','DELIVERY','COMPLETE');
  • 특정 시간에 발생한 주문의 가격과 개수를 구하는 쿼리이다. 스케줄러로 실행했기 때문에 해당 시간에 주문이 없을 수 있다. RuntimeException이 발생해서 이유가 무엇인지 찾아보니, count는 제대로 값이 0으로 들어갔지만, sum에는 NULL이 들어갔고 이를 변환하는 과정에서 NullPointerException이 발생했다.
  • https://dev.mysql.com/doc/refman/8.4/en/problems-with-null.html
  • 위의 공식문서를 참고하면 Aggregate (group) functions such as COUNT(), MIN(), and SUM() ignore NULL values. COUNT, MIN, SUM은 NULL 값을 무시하고 계산한다고 한다. COUNT()의 경우 NULL이 아닌 값의 개수를 세기 때문에 0이 나오지만, SUM()의 경우 NULL끼리 값을 더해도 NULL이기 때문이다.

profile
꾸준하게

0개의 댓글