목차
백분율 변환
import java.text.DecimalFormat;
public class PercentCalcTest {
public static final String PERCENT_PATTERN = ".##";
/**
* 백분율로 변환
* @param total : Max Size
* @param range : idle or used size
* @param pattern
* @return
*/
public static String parsePercent(double total, double range, String pattern) {
DecimalFormat df = new DecimalFormat(pattern);
return df.format((range * 100.0) / total);
}
public static void main(String[] args) {
System.out.println("백분율 : " + parsePercent(100000, 43500, PERCENT_PATTERN) + "%");
}
}
결과
백분율 : 43.5%
계산식은 부분 / 전체 × 100이다. 예제의 range=43,500, total=100,000을 넣으면 43.5가 나온다. 출력에 %를 직접 붙였으므로 DecimalFormat 패턴에는 %를 넣지 않았다. 패턴에 %를 넣으면 포맷터가 다시 100을 곱한다.
현재 parsePercent는 total이 0일 때 무한대 또는 NaN을 만들 수 있다. 입력 경계를 확인하는 코드는 다음과 같다.
static double percent(double total, double part) {
if (!Double.isFinite(total) || !Double.isFinite(part) || total <= 0) {
throw new IllegalArgumentException("전체는 양수, 입력은 유한한 숫자여야 합니다.");
}
return part * 100.0 / total;
}
part가 total보다 커도 계산 자체는 가능하다. 사용률처럼 0~100%만 허용하는 도메인이라면 part >= 0 && part <= total을 추가로 검증한다. 소수점 자리수와 반올림 방식은 출력 요구에 맞춰 별도로 정한다.
반올림과 로캘을 분리하기
DecimalFormat(".##")은 소수점 앞의 0을 생략할 수 있어 0.5를 .5처럼 표현한다. 화면에 수치를 보여줄 목적이라면 "0.##"가 읽기 쉽다. 포맷터는 실행 환경의 로캘에 따라 소수점 문자를 다르게 표시할 수 있다. 로그나 외부 API처럼 기계가 읽는 출력은 로캘을 명시하고, 사용자 화면은 사용자 로캘에 맞춘다. DecimalFormat 객체는 스레드 사이에 공유하지 않는 편이 안전하다.
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
DecimalFormat format = new DecimalFormat("0.##", DecimalFormatSymbols.getInstance(Locale.ROOT));
System.out.println(format.format(1.0 / 8.0 * 100.0) + "%"); // 12.5%
위 수치는 1 / 8 × 100 = 12.5다. 비율을 저장하거나 비교할 때는 원래 분자·분모를 유지하고, 반올림은 표시 직전에 적용한다. 표시된 12.5%를 다시 계산에 쓰면 반올림 오차가 누적될 수 있다. 화폐나 법적 정산처럼 소수점 규칙이 중요한 곳은 double보다 BigDecimal과 명시적 RoundingMode를 선택한다.
원래 메서드의 인자 이름 range는 부분값을 뜻하지만 범위처럼 읽힌다. part, total처럼 도메인 의미를 드러내고, 총합이 0일 때의 정책을 호출자에게 명시한다. 파일 사용률이라면 0/0은 “0%“로 볼지 “계산 불가”로 볼지 업무 규칙이 필요하다. 단순히 NaN을 문자열로 노출하는 것은 피한다.