如果您只想限制小数位数,一个简单的解决方案是
public static String formatDecimal(BigDecimal b, int max) {
return b.setScale(max, RoundingMode.HALF_EVEN).stripTrailingZeros().toEngineeringString();
}
现在,您还想根据整数部分中的数字来限制小数位数。我认为使用 DecimalFormat 和 MessageFormat 类可以更好地发挥作用,这是我可以提供的,它通过了测试用例,但我不认为它那么健壮。您可以尝试创建一个更好的算法来处理所有不同的情况。
public static String formatDecimal(BigDecimal b, int max) {
// trivial case
String bs = b.stripTrailingZeros().toPlainString();
if (bs.length() <= max) {
return bs;
}
// determine the max integer = 1.0Emax
String maxInteger = "1" + StringUtils.repeat("0", max - 1);
// determine the min fraction = 1.0E-max
String minFraction = "0." + StringUtils.repeat("0", max - 2) + "1";
// get the integer part
String integerPart = String.valueOf(b.intValue());
// make the pattern like ###.### with the correct repetition
String pattern = StringUtils.repeat("#", max - integerPart.length()) + "." + StringUtils.repeat("#", max - 1 - integerPart.length());
// play with Message format, using a choice to determine when to use the exponential format
MessageFormat fmt = new MessageFormat( //
"{0,choice," + minFraction + "<{0,number,'0.#E0'}|0.1#{0,number,'" + pattern + "'}|" + maxInteger + "<{0,number,'0.#E0'}}" //
);
// time to format the number
return fmt.format(new Object[] {b});
}
另一个使用 if/else 的解决方案可以像这样开始:
public static String formatDecimal(BigDecimal b, int max) {
// trivial case
if (b.toPlainString().length() <= max)
return b.toPlainString();
else {
// between 0 and 1, or superior than 1*10^max, better use the exponential notation
if ((b.compareTo(BigDecimal.ZERO) > 0 && b.compareTo(new BigDecimal("0.01")) < 0) //
|| (b.compareTo(new BigDecimal("1" + StringUtils.repeat("0", max - 1))) > 0)) {
return new DecimalFormat("#.#E0").format(b);
} else { // set Scale for fraction, better keep integer part safe
String sb = b.toPlainString();
return b.setScale(max - sb.indexOf(".") - 1, RoundingMode.HALF_EVEN).stripTrailingZeros().toPlainString();
}
}
}