✍ 백준 26575


케이스가 주어지고, 케이스마다 사료를 사기위한 총 금액을 구하는 문제이다. (문제는 원문을 gpt로 번역하였다.)
import java.io.*;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int caseNo = Integer.parseInt(br.readLine());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < caseNo; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
// dogs를 int로 두면 NumberFormatException이 떠서 double로 두었다.
double dogs = Double.parseDouble(st.nextToken());
double food = Double.parseDouble(st.nextToken());
double price = Double.parseDouble(st.nextToken());
// 소수점 2자리까지 반올림
double totalPrice = Math.round(dogs * food * price * 100) / 100.0;
sb.append("$" + totalPrice + "\n");
}
sb.deleteCharAt(sb.length() - 1);
bw.write(sb.toString());
bw.flush();
bw.close();
br.close();
}
}
먼저 케이스를 읽고, 케이스만큼 totalPrice를 구하고 소수점 둘째 자리까지 반올림하는 방식으로 짜보았다.

그런데 틀렸다고 떠버렸다..
그래서 다른 방식으로 찾아보니 String.format()
을 썼더니 정답으로 처리되었다. 차이점이 무엇일까?
📌 소수점 반올림 하는법
1. Math.round()
+ 곱하고 나누기
double value = 11.256;
double rounded = Math.round(value * 100) / 100.0;
System.out.println(rounded); // 출력: 11.26
double value2 = 11.2;
double rounded2 = Math.round(value2 * 100) / 100.0;
System.out.println(rounded2); // 출력: 11.2
11.256을 소수 둘째 자리까지 반올림하려면 100을 곱하고 100.0으로 나누면 된다.
반올림 할게 없는 11.2를 반올림하면 그대로 11.2 로 출력된다.
2. String.format()
와 System.out.printf()
double value = 11.256;
System.out.printf("%.2f\n", value); // 출력: 11.26
String result = String.format("%.2f", value);
System.out.println(result); // 출력: 11.26
double value2 = 11.2;
System.out.printf("%.2f\n", value); // 출력: 11.20
String result = String.format("%.2f", value);
System.out.println(result); // 출력: 11.20
String.format()
을 사용하여 숫자를 원하는 형식의 문자로 바꿀 수 있다.format(형식, 값)
의 형태이고, 실수는 %f, f앞의 .2는 2번째 자리까지 반올림하여 나타낸다는 뜻이다.System.out.printf()
는 형식을 정하여 출력하는 출력전용 메서드이고,
형태는String.format()
와 동일하다.반올림 할게 없는 11.2를 출력하면 11.20이 되는 것처럼, 소수의 남은 부분은 0으로 출력한다.
3. BigDecimal 과 RoundingMode
double d1 = 0.1;
double d2 = 0.2;
System.out.println(d1 + d2); // 결과: 0.30000000000000004
BigDecimal bd1 = new BigDecimal("0.1");
BigDecimal bd2 = new BigDecimal("0.2");
System.out.println(bd1.add(bd2)); // 결과: 0.3
BigDecimal
은 정확한 소수 계산을 하기 위해 Java에서 제공하는 클래스다.float
,double
은 근사치로 계산돼서, 정확하지 않은 결과가 나올 수 있어서 정밀한 수치 계산이 필요한 경우엔BigDecimal
로 계산을 하는것이 안전하다.
BigDecimal bd = new BigDecimal(0.1);
System.out.println(bd); // 출력: 0.100000000000000005551115123125...
BigDecimal bd = new BigDecimal("0.1");
System.out.println(bd); // 출력: 0.1 (정확함!)
BigDecimal
은 생성할때 인자를 int, double, BigInteger, String 로 받을 수 있지만,
String으로 받는게 가장 정확하다.
BigDecimal의 주요 메서드
메서드 | 설명 |
add() | 덧셈 |
subtract() | 뺄셈 |
multiply() | 곱셈 |
divide() | 나눗셈 (주의: 0 나누기나 정밀도 지정 필요) |
setScale(int, RoundingMode) | 자리수 반올림 지정 |
RoundingMode
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
BigDecimal result = a.divide(b); // ❌ ArithmeticException 발생!
BigDecimal
의divide()
메서드는 나눌때 딱 나누어 떨어지지 않으면, 무한소수가 되어 ArithmeticException 이 발생하게 된다.그래서 나눗셈은 정밀도 지정이 필요해
RoundingMode
클래스가 필요하다.
RoundingMode 종류
RoundingMode | 설명 |
UP | 무조건 올림 (절댓값 기준) |
DOWN | 무조건 내림 (절댓값 기준) |
CEILING | 양수는 올림, 음수는 내림 |
FLOOR | 양수는 내림, 음수는 올림 |
HALF_UP | 5 이상이면 올림 (일반적인 반올림) |
HALF_DOWN | 5 이상이어도 내림 |
HALF_EVEN | 5일 경우 가장 가까운 짝수 쪽으로 반올림 |
UNNECESSARY | 반올림 없이 정확히 떨어져야 함. 안 그러면 예외 발생 |
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
// 소수점 아래 2자리까지 표현 + 반올림 방식 지정
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
System.out.println(result); // 출력: 3.33
BigDecimal num = new BigDecimal("2.456");
// 소수점 아래 2자리까지 표현 + 반올림
System.out.println(num.setScale(2, RoundingMode.HALF_UP)); // 출력: 2.46
BigDecimal num2 = new BigDecimal("2.4");
System.out.println(num.setScale(2, RoundingMode.HALF_UP)); // 출력: 2.40
백준문제에서 오류가 떴던 이유는 Math.round()
를 쓰면 소수점 첫째 자리가 주어지면 첫째자리까지만 표현을 해주기 때문이었다. 따라서 String.format()
을 써야 원하는 형식을 맞출 수 있었다.
다음은 String.format을 이용하여 해결한 코드이다.
import java.io.*;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int caseNo = Integer.parseInt(br.readLine());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < caseNo; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
double dogs = Double.parseDouble(st.nextToken());
double food = Double.parseDouble(st.nextToken());
double price = Double.parseDouble(st.nextToken());
// String.format을 사용하여 소수점 2자리까지 반올림
sb.append(String.format("$%.2f\n", dogs * food * price));
}
sb.deleteCharAt(sb.length() - 1);
bw.write(sb.toString());
bw.flush();
bw.close();
br.close();
}
}
📚마무리
소수점 반올림 하는 방법은 Math.round(), String.format(), BigDemical 이 있다.
좀 더 정확한 소수 계산을 위해선 BigDemical 클래스를 사용한다.
원하는 형식으로 출력하고 싶다면, String.format()을 사용하는것이 좋다.