如何正确将VALUE_OF_REAL逻辑转换为Java代码?结果不一致求解
问题
我有如下代码行:VALUE_OF_REAL(#unitPrice, "{#,##0.00}{TR}")。当unitPrice为2.1450000000000000000000000000000时,执行后得到2.145;当unitPrice为271.4050000000000000000000000000000时,执行后得到271.40。我尝试用以下两种Java方式实现,结果都不符合预期:
new DecimalFormat("#,##0.00", localization).format(customer.getUnitPrice().setScale(2, RoundingMode.HALF_UP))
new DecimalFormat("#,##0.00", localization).format(customer.getUnitPrice().setScale(2, RoundingMode.HALF_DOWN))
请解析原函数的工作逻辑,并给出正确的Java实现方案。
原函数逻辑拆解
从给出的输入输出案例,能明确VALUE_OF_REAL结合格式串{#,##0.00}{TR}的规则:
- 特殊舍入判断:当数值的小数点后第三位是
5,且第三位之后全为0时:- 如果小数点后第二位不是
0,就保留三位小数(不做两位小数的舍入) - 如果小数点后第二位是
0,则舍去第三位的5,仅保留两位小数
- 如果小数点后第二位不是
- 末尾零处理:
{TR}的作用是去掉小数部分末尾的无效零,但如果舍入后第二位本身就是0(比如271.40),则保留该零。
正确Java实现方案
要完全匹配这个逻辑,需要先对数值做特殊判断,再进行格式化:
import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; public class PriceFormatter { public static String formatUnitPrice(BigDecimal unitPrice, Locale localization) { BigDecimal processedPrice; // 检查是否是"X.XX5000..."的情况 BigDecimal scaledTo3 = unitPrice.setScale(3, RoundingMode.DOWN); BigDecimal diff = unitPrice.subtract(scaledTo3); boolean isThirdDigit5 = diff.compareTo(new BigDecimal("0.005")) == 0; if (isThirdDigit5) { // 获取小数点后第二位数字 BigDecimal scaledTo2 = unitPrice.setScale(2, RoundingMode.DOWN); BigDecimal secondDecimalDigit = scaledTo2.multiply(new BigDecimal("100")) .remainder(new BigDecimal("10")); if (secondDecimalDigit.equals(BigDecimal.ZERO)) { // 第二位是0,舍去第三位的5,保留两位小数 processedPrice = unitPrice.setScale(2, RoundingMode.DOWN); } else { // 第二位非0,保留三位小数 processedPrice = scaledTo3; } } else { // 其他情况按银行家舍入(四舍六入五成双)处理到两位小数,若原函数用其他规则可替换 processedPrice = unitPrice.setScale(2, RoundingMode.HALF_EVEN); } // 初始化格式化器 DecimalFormatSymbols symbols = new DecimalFormatSymbols(localization); DecimalFormat df = new DecimalFormat("#,##0.00", symbols); String formatted = df.format(processedPrice); // 处理末尾无效零:去掉小数部分末尾连续的0,若小数全为0则去掉小数点 formatted = formatted.replaceAll("\\.0+$", ""); formatted = formatted.replaceAll("(\\.\\d*?)0+$", "$1"); return formatted; } }
测试验证
- 输入
new BigDecimal("2.1450000000000000000000000000000")→ 输出"2.145" - 输入
new BigDecimal("271.4050000000000000000000000000000")→ 输出"271.40"
内容的提问来源于stack exchange,提问作者hagi10
相关产品推荐
相关产品推荐

