소수점 반올림하기 (백준 26575)

백준 반올림하기
Javabaekjoonround
avatar
2025.04.14
·
8 min read

백준 26575

51175118

케이스가 주어지고, 케이스마다 사료를 사기위한 총 금액을 구하는 문제이다. (문제는 원문을 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를 구하고 소수점 둘째 자리까지 반올림하는 방식으로 짜보았다.

5119

그런데 틀렸다고 떠버렸다..
그래서 다른 방식으로 찾아보니 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앞의 .22번째 자리까지 반올림하여 나타낸다는 뜻이다.

  • 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 발생!
  • BigDecimaldivide() 메서드는 나눌때 딱 나누어 떨어지지 않으면, 무한소수가 되어 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()을 사용하는것이 좋다.







- 컬렉션 아티클