Java DecimalFormat特定场景下格式化异常原因咨询
关于Java DecimalFormat格式化double的异常问题分析
问题现象
第一组异常案例
// 如预期返回"0.1" (new DecimalFormat("0.#", new DecimalFormatSymbols(Locale.US))).format(0.05); // 如预期返回"0.01" (new DecimalFormat("0.##", new DecimalFormatSymbols(Locale.US))).format(0.005); // 预期返回"0.001",实际返回"0" (new DecimalFormat("0.###", new DecimalFormatSymbols(Locale.US))).format(0.0005); // 预期返回"0.0001",实际返回"0" (new DecimalFormat("0.####", new DecimalFormatSymbols(Locale.US))).format(0.00005);
为何第三、四条语句返回"0"?
第二组异常案例
// 如预期返回"1.105" (new DecimalFormat("#.###")).format(1.1045); // 预期返回"0.105",实际返回"0.104"(原因何在?) (new DecimalFormat("#.###")).format(0.1045);
核心原因:double类型的精度丢失
Java中的double是IEEE 754标准的双精度浮点数,它无法精确表示所有十进制小数,只能存储近似值:
- 像
0.0005这样的小数,实际在内存中存储的近似值是0.0004999999999999999...,比真实值略小;当用0.###格式(保留三位小数)格式化时,第四位小数是4,触发舍去操作,最终得到0.000,显示为"0"。同理0.00005的存储值更小,格式化后也会显示"0"。 - 对于
1.1045和0.1045,两者的存储近似值不同:1.1045实际存储为1.1045000000000002...(略大于真实值),格式化到三位小数时会进一位得到1.105;而0.1045实际存储为0.10449999999999999...(略小于真实值),格式化时舍去第四位的4,得到0.104。
解决方案:使用BigDecimal避免精度问题
要彻底解决这类问题,应该用BigDecimal来替代double,它可以精确表示十进制小数:
// 方式1:用字符串构造BigDecimal(推荐,避免double转BigDecimal时的精度问题) BigDecimal num1 = new BigDecimal("0.0005"); BigDecimal num2 = new BigDecimal("0.1045"); // 方式2:如果必须从double转换,使用BigDecimal.valueOf() BigDecimal num3 = BigDecimal.valueOf(0.0005); // 格式化示例 DecimalFormat df = new DecimalFormat("0.###", new DecimalFormatSymbols(Locale.US)); System.out.println(df.format(num1)); // 输出"0.001" System.out.println(df.format(num2)); // 输出"0.105"
内容的提问来源于stack exchange,提问作者Gokay
相关产品推荐
相关产品推荐

