월드전자는 노트북을 제조하고 판매하는 회사이다. 노트북 판매 대수에 상관없이 매년 임대료, 재산세, 보험료, 급여 등 A만원의 고정 비용이 들며, 한 대의 노트북을 생산하는 데에는 재료비와 인건비 등 총 B만원의 가변 비용이 든다고 한다.
예를 들어 A=1,000, B=70이라고 하자. 이 경우 노트북을 한 대 생산하는 데는 총 1,070만원이 들며, 열 대 생산하는 데는 총 1,700만원이 든다.
노트북 가격이 C만원으로 책정되었다고 한다. 일반적으로 생산 대수를 늘려 가다 보면 어느 순간 총 수입(판매비용)이 총 비용(=고정비용+가변비용)보다 많아지게 된다. 최초로 총 수입이 총 비용보다 많아져 이익이 발생하는 지점을 손익분기점(BREAK-EVEN POINT)이라고 한다.
A, B, C가 주어졌을 때, 손익분기점을 구하는 프로그램을 작성하시오.
첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 21억 이하의 자연수이다.
첫 번째 줄에 손익분기점 즉 최초로 이익이 발생하는 판매량을 출력한다. 손익분기점이 존재하지 않으면 -1을 출력한다.
1000 70 170
11
3 2 1
-1
이 문제에서 생각해봐야 할 점은 '손익분기점이 존재하지 않는 경우'를 구현하는 부분이다.
조건이 성립하지 않으면 반복문을 빠져나와 -1을 출력해야 하는데, 노트북 대수가 정확히 주어져 있지 않기 때문에 조건을 어떻게 지정해야 하나 싶을 것이다. 그렇다고 무한정 루프를 실행시킬 수도 없는 노릇 아닌가.
다행히도 노트북 대수를 int
타입으로 지정하면, int
타입의 범위값을 초과할 경우 자연스레 반복문을 빠져 나오게 된다.
하지만 여기서 또 문제가 발생하는데, 아무리 -1
을 대입해도 -2147483648
이 출력된다는 것이다. 다음 표를 살펴보자.
[Java 정수 타입 자료형의 표현 범위]
자료형 | 사이즈 | 표현 범위 |
---|---|---|
byte | 1 byte | -128 ~ 127 |
short | 2 byte | -32768 ~ 32767 |
int | 4 byte | -2147483648 ~ 2147483647 |
long | 8 byte | -922337036854775808 ~ 9223372036854775807 |
위의 표를 보면, int
타입의 범위는 -2147483648
~ 2147483647
이다. java
에서는 정수값이 허용된 범위를 초과하게 되면 시스템 에러가 발생하여 의도한 수와는 다른 수가 저장되는 이른바 Overflow가 발생하게 된다.
근데 여기서 이상한 점이 있다. 이 문제에서는 최대값을 초과하면 2147483648
이 출력되야 하는데, 이상하게도 -2147483648
이 출력된다. 왜일까?
그 이유는 값을 2진수로 출력해보면 알 수 있다.
다음 예제를 보자.
System.out.println(Integer.toBinaryString(-2147483648));
// 결과 : 10000000 00000000 00000000 00000000
System.out.println(Integer.toBinaryString(-1));
// 결과 : 11111111 11111111 11111111 11111111
System.out.println(Integer.toBinaryString(1));
// 결과 : 00000000 00000000 00000000 00000001
System.out.println(Integer.toBinaryString(2147483647));
// 결과 : 01111111 11111111 11111111 11111111
java에서 기본 정수 타입은 signed
이므로, 최상위 비트를 부호 비트로 사용한다. 그래서 2147483648
가 int
의 범위에서는 -2147483648
로 출력되는 것이다.
이를 방지하기 위해서는 정수값에 대한 검증을 해주는 게 좋으나, 이 문제에서는 그 부분까지 다룰 필요는 없는 것 같아서 건너뛰도록 하겠다.
다시 문제로 돌아와서, 그렇다면 로직을 어떻게 짜는 게 좋을까?
다른 부분은 조금만 생각하면 금방 풀 수 있을 것 같으니 손익분기점을 넘지 않는 부분 관련해서만 서술하도록 하겠다.
while
문을 노트북 대수 n
이 int
타입의 최대값보다 작은 동안(n < Integer.MAX_VALUE
)만 실행시키며 n
의 값을 증가시킨다.n <= Integer.MAX_VALUE
) 루프가 한 번 더 실행하여 n
의 값이 범위를 벗어나 -2147483648
이 되기 때문이다.n
의 값이 int
의 최대값이 되므로 여기서 n
을 -1
로 조정해준다.글만 읽으면 이해가 잘 안 갈수도 있다. 아래 코드를 보면 좀 더 쉽게 이해할 수 있을 것이다.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
long a = scanner.nextInt(); // 고정비용
long b = scanner.nextInt(); // 가변비용
long c = scanner.nextInt(); // 노트북 가격
scanner.close();
int n = 1; // 노트북 대수
// 손익분기점 = 총 수입(c*n) > 총 비용(a+(b*n))
while(c*n <= a+(b*n) && n < Integer.MAX_VALUE) // 손익분기점을 넘지 않고 정수 n이 범위값보다 작은 동안
n++; // 최대값도 포함시키면 오버플로우로 인해 -2147483648이 출력됨
if(n == Integer.MAX_VALUE) // 루프 빠져나왔을 때 노트북 대수가 정수의 최대값이라면(손익분기점 존재 x)
n = -1;
System.out.println(n);
}
}