본문 바로가기
카테고리 없음

[Java] / 연산자와 Math.floor()의 함정, 그리고 음수 나눗셈의 비하인드

by 프로P 2026. 6. 5.

알고리즘 문제를 풀거나 수식을 코드로 옮기다 보면 내림 함수($\lfloor x \rfloor$) 표기를 자주 마주치게 됩니다. 보통 Java에서 자연수를 다룰 때는 고민 없이 / 연산자를 사용해 소수점을 절삭하곤 하는데요.

"과연 음수 연산에서도 / 연산자가 수학적인 내림(Floor)처럼 동작할까?" 라는 의문에서 출발해, Java의 동작 방식과 안전한 대안까지 정리해 보았습니다.

1. Java의 / 연산자는 '내림'이 아니라 '절삭'이다

결론부터 말하자면, Java에서 정수끼리 나누는 x / y 연산은 수학의 내림(Floor)과 다르게 동작합니다. Java 공식 스펙(JLS) 기준으로 정수 나눗셈은 '0을 향해 버림(Round toward zero)'하는 Truncation(절삭) 방식을 취하기 때문입니다.

양수를 나눌 때는 소수점을 버리는 방향이 '더 작은 정수(내림)'로 향하기 때문에 수학적 정의와 일치합니다. 하지만 음수가 포함되면 이야기가 달라집니다.

  • 양수 연산 (5 / 3)
    • $1.666... \rightarrow$ 0을 향해 버리면 1 (수학적 내림과 동일)
  • 음수 연산 (-5 / 3)
    • $-1.666... \rightarrow$ 0을 향해 버리면 -1
    • 수학적인 내림($\lfloor -5/3 \rfloor$) 기준으로는 $-1.666...$보다 작은 최대 정수여야 하므로 -2가 되어야 하지만, Java의 / 연산 결과는 -1이 나옵니다.

수직선 기준으로 보면 음수 나눗셈 시 오히려 값이 커지는(올림 방향) 현상이 발생하게 되는 것이죠.

2. Math.floor()는 무조건 내림이지만... 타입이 아쉽다

그렇다면 자바의 내장 API인 Math.floor()를 쓰면 해결될까요?

Java
 
System.out.println(Math.floor(-1.666)); // 출력: -2.0

Math.floor()는 음수든 양수든 예외 없이 수직선의 왼쪽(바닥 방향)으로 값을 떨어뜨리기 때문에 수학적 정의를 완벽히 만족합니다.

하지만 한 가지 아쉬운 점이 있습니다. Math.floor()는 인자로 double을 받고 반환형도 double입니다. 만약 배열의 인덱스나 정수형 변수에 이 값을 그대로 담으려면 매번 (int)로 명시적 형변환(Casting)을 해줘야 하는 번거로움이 있고, 실수 연산 자체의 미세한 오버헤드도 무시할 수 없습니다.

3. Java 8의 숨은 꿀템: Math.floorDiv()

정수형 스케일을 유지하면서 음수에서도 안전한 수학적 내림 연산을 수행하고 싶다면, Java 8부터 추가된 Math.floorDiv()를 사용하면 됩니다.

Java
 
int result = Math.floorDiv(-5, 3); 
System.out.println(result); // 출력: -2

이 메서드는 내부적으로 정수 연산을 수행하면서도 음수일 때 수학적 내림 규칙($\lfloor a / b \rfloor$)을 완벽히 따르도록 구현되어 있습니다.

  • int를 넣으면 int를 반환하고, long을 넣으면 long을 반환하므로 불필요한 타입 캐스팅이 발생하지 않습니다.

요약 및 한줄평

  • 양수 연산만 보장된다면? 성능이 가장 빠른 일반 / 연산자를 써도 무방하다.
  • 음수 좌표 이동, 음수 주기 계산 등 엣지 케이스가 있다면? / 연산자는 버그를 유발하므로 Math.floorDiv()를 적극 활용하자.