使用BigDecimal与DecimalFormat将Double转Float时小数位精度异常问题
浮点数精度问题:Double转Float保留两位小数时的异常原因
用户测试代码:
import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; class Scratch { private static final DecimalFormat df = new DecimalFormat("0.00"); public static void main(String[] args) { Double worksAsIWouldExpect = 262143.05; Double worksNotAsIWouldExpect = 262144.05; convertAndPrint(worksAsIWouldExpect); //DecimalFormat: 262143.05 //Big Decimal: 262143.05 convertAndPrint(worksNotAsIWouldExpect); //DecimalFormat: 262144.06 //Big Decimal: 262144.06 } public static void convertAndPrint(Double doubleValue) { //DecimalFormat String stringValueDf = df.format(doubleValue); float floatValue = Float.parseFloat(stringValueDf); System.out.println("DecimalFormat: " + floatValue); //Big Decimal BigDecimal decimalValue = new BigDecimal(doubleValue.toString()); decimalValue = decimalValue.setScale(2, RoundingMode.HALF_DOWN); floatValue = decimalValue.floatValue(); System.out.println("Big Decimal: " + floatValue); } }
执行输出:
DecimalFormat: 262143.05 Big Decimal: 262143.05 DecimalFormat: 262144.06 Big Decimal: 262144.06
核心原因解析
- 十进制小数的二进制存储局限性:像
0.05这类十进制小数,无法被精确转换为二进制浮点数,只能以近似值存储。不管是Double(64位双精度)还是Float(32位单精度),存储的都是0.05的近似值,而非精确值。 - Double的近似值偏差:
262144.05作为Double类型存储时,实际值是略大于262144.05的近似值;而262143.05的Double近似值,刚好更接近262143.05这个十进制数。 - Float的精度上限限制:Float的有效位数仅约6-7位,当把
262144.05的Double近似值转成Float时,Float无法精确表示这个略大的近似值,只能取最接近的可表示值——也就是262144.06。而262143.05数值范围更小,Float的精度足够覆盖其近似值,所以能得到预期结果。 - 代码中的隐性误区:用
doubleValue.toString()初始化BigDecimal,看似能拿到精确值,但Double的toString方法只会输出最接近的十进制表示,本质还是基于那个略大的近似值。后续转成Float时,依然受限于Float的精度,最终结果还是262144.06。
内容的提问来源于stack exchange,提问作者Stefan Greil
相关产品推荐
相关产品推荐

