[JAVA] 소수점 반올림 정리

Jongyhyuk Kim·2021년 2월 10일
0

TIP

목록 보기
3/3
post-thumbnail

PS를 하던 소수점으로 표현해야하는 문제를 보고는 학부 시절 C언어를 배우며 익힌 형식 문자를 통해 풀었지만 다른 사람들의 풀이를 보고 성능면에서도 큰 차이가 있다는 사실을 확인하며 개인적으로 정리해보고자 한다.

String format형식

%[argument_index$][flags][width]conversion

%와 conversion은 필수 항목
conversion: 출력되는 데이터 타입
Ex. s(문자열), d(정수), x(16진수), f(실수)

System.out.println("[example]");
// 위치를 확인하기 위해 1~0의 숫자를 반복 출력
System.out.println("12345678901234567890");
// %s를 이용하여 문자열 출력
System.out.println(String.format("%s, %s", "KOREA", "JAPAN"));
// width +  argument_index 옵션
System.out.println(String.format("%2$10s%1$10s", "KOREA", "JAPAN"));
// flag 옵션
System.out.println(String.format("%-10s%-10s", "KOREA", "JAPAN"));


width, argument_index, flag를 통해 다양한 옵션으로 문자열을 표현할 수 있다.

이번 PS에서 소수점 3자리 표기가 필요했는데 필자는 .3f%를 통해 소수점 3자리를 지정할 수 있었다.

Math.round 방식

자바의 대표적인 수학 모듈인 Math 클래스에서 소수점을 처리하는 기능을 제공
다만, Math.round는 기본적으로 소수점 위치에서 반올림을 하게되고 원하는 위치를 반올림하기 위해서는 별도의 인자값을 넣는 것이 아니라 그만큼 소수점을 Shift해야 한다.

System.out.println("[example]");
double a = 12.3456789;
System.out.println(a*100);
System.out.println((double)Math.round(a*100));
System.out.println((double)Math.round(a*100)/100);

NumberFormat 방식

한 번도 들어보지 못한 NumberFormat 방법
NumberFormat 클래스는 수에 대한 포괄적인 포맷 기능을 제공, 정적 메소드로 new 연산자를 사용하여 객체를 호출할 필요가 없다.

//현재 지역의 화폐 양식을 나타내는 NumberFormat 객체를 return
static NumberFormat getCurrencyInstance()
//현재 지역의 백분율 양식을 나타내는 NumberFormat 객체를 return
static NumberFormat getPercentInstance()
//현재 디폴트 locale에 대한 범용 수치 format을 리턴
static NmuberFormat getNumberInstance()

NumberFormat으로 소수점 출력을 처리하기 위해서는 별도의 메소드를 지정해줘야 한다. 하지만 이는 소수점 처리를 자주 쓰게 된다면 소스를 보다 깔끔하게 처리하고 유지보수 등으로 봤을 때 좋을 수 있다는 장점이 있다. 다음과 같이 정리해보자.

public static void main(String[] args) {
	double a = 12.3456789;
    System.out.println(cutDecimal(2, a));
}
public static String cutDecimal(int cutSize, double value) {
	NumberFormat nf = NumberFormat.getNumberInstance();
    nf.setMaximumFractionDigits(cutSize);
    nf.setGroupingUsed(false);
    return nf.format(value);
}

성능 비교

이번 조사를 통해 무엇보다 값진 배움을 얻은 것은 성능 부분에서의 차이이다.
기본 개념으로 PS를 해결하자는 고집이 있었는데 다음 결과를 통해 지속적인 공부를 통해 다양한 클래스 활용으로 효율을 높이는 것이 보다 중요하다는 것을 깨달을 수 있는 계기가 되었다.

		long startTime = System.currentTimeMillis();
		double a = 12.3456789; 
		double dummy = 0.0;
		
		for(int i = 0; i < 100000; i++) cutDecimal(2, a);
		long stop1 = System.currentTimeMillis();
		System.out.println((stop1-startTime) + "(ms)");
		
		for(int i = 0; i < 100000; i++) String.format("%.2f", a);
		long stop2 = System.currentTimeMillis();
		System.out.println((stop2-stop1) + "(ms)");
		
		for(int i = 0; i < 100000; i++) dummy = (double)Math.round(a*100)/100; 
		long stop3 = System.currentTimeMillis();
		System.out.println((stop3-stop2) + "(ms)");

앞서 다룬 방법의 속도를 NumberFormat, String.format, Math.round 순으로 비교해보았다. 의미있는 속도를 위해 100만번씩 연산을 수행해보았는데 다음 같이 성능면에서 상당한 차이를 볼 수가 있다.

Math.round > String.format > NumberFormat 순으로 상황에 따라 다르겠지만 앞으로 소수점과 관련된 코드를 잘 때는 Math.round를 default로 잡고 가야겠다고 생각한다.

이 Source을 제공해주신 '강철현인'님 감사드립니다.

참고 사이트
http://blog.devez.net/100
https://needjarvis.tistory.com/544
https://hyeonstorage.tistory.com/162

profile
Bellhyuk, Bottom out

0개의 댓글