Double使用注意事项
目录
- 数据精度问题
- BigDecimal的正确使用
- 构造陷阱
- 数值比较
- 除法
- 舍入控制 `RoundingMode`
数据精度问题
Java开发中,Double
类作为包装类用于处理双精度浮点数。浮点数double
无法精确表示某些十进制小数(如0.1
),导致运算结果出现误差
double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 输出 0.30000000000000004,而非0.3
需要精确计算的场景需要使用:BigDecimal
,并通过字符串构造避免初始精度丢失。
BigDecimal d1 = new BigDecimal("0.1");
BigDecimal d2 = new BigDecimal("0.2");
System.out.println(d1.add(d2)); // 0.3
Double 比较推荐使用 Double.
compare(a, b)
double a = 0.1;
double b = 0.1;
System.out.println(a == b); // trueDouble aD = 0.1;
Double bD = 0.1;
System.out.println(aD == bD); // false
System.out.println(Double.compare(aD, bD) == 0); // true
BigDecimal的正确使用
对于需要精确计算的场景,使用BigDecimal
。
构造陷阱
避免用double
构造BigDecimal
,否则传入的是不精确的二进制值。
double v = 0.946;
System.out.println(v); // 输出正确,0.946
// 直接转 BigDecimal,实际内部值是不精确的二进制值,导致截取3位小数结果错误
double vv = new BigDecimal(v).setScale(3, RoundingMode.DOWN).doubleValue();
System.out.println(vv); // 输出错误值 0.945
正确做法:BigDecimal
(字符串构造)
double vvv = new BigDecimal(String.valueOf(v)).setScale(3, RoundingMode.DOWN).doubleValue();
System.out.println(vvv); // 输出正确,0.946
数值比较
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1");
System.out.println(a.compareTo(b) == 0); // true,数值相等
除法
必须指定舍入模式和精度,处理无限小数
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
// 指定保留4位小数,四舍五入
BigDecimal result = a.divide(b, 4, RoundingMode.HALF_UP); // 3.3333
不处理无限小数会抛出异常 ArithmeticException
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
a.divide(b); // 抛出 ArithmeticException
舍入控制 RoundingMode
RoundingMode.UP 远离零方向舍入 2.5 → 3, -2.5 → -3
RoundingMode.DOWN 向零方向舍入 2.5 → 2, -2.5 → -2
RoundingMode.CEILING 向正无穷方向舍入 2.5 → 3, -2.5 → -2
RoundingMode.FLOOR 向负无穷方向舍入 2.5 → 2, -2.5 → -3
RoundingMode.HALF_UP 四舍五入(常用) 2.5 → 3, 2.4 → 2
RoundingMode.HALF_DOWN 五舍六入 2.5 → 2, 2.6 → 3
示例
// 测试数值
BigDecimal number = new BigDecimal("2.55");
String label = "正数 2.55";
int newScale = 1;System.out.println("--- 测试数值: " + label + " ---");// UP:远离零方向舍入
System.out.println("UP : " + number.setScale(newScale, RoundingMode.UP));// DOWN:向零方向舍入
System.out.println("DOWN : " + number.setScale(newScale, RoundingMode.DOWN));// CEILING:向正无穷方向舍入
System.out.println("CEILING : " + number.setScale(newScale, RoundingMode.CEILING));// FLOOR:向负无穷方向舍入
System.out.println("FLOOR : " + number.setScale(newScale, RoundingMode.FLOOR));// HALF_UP:四舍五入
System.out.println("HALF_UP : " + number.setScale(newScale, RoundingMode.HALF_UP));// HALF_DOWN:五舍六入
System.out.println("HALF_DOWN : " + number.setScale(newScale, RoundingMode.HALF_DOWN));
结果展示,
--- 测试数值: 正数 2.55 ---
UP : 2.6
DOWN : 2.5
CEILING : 2.6
FLOOR : 2.5
HALF_UP : 2.6
HALF_DOWN : 2.5
负数注意 UP 和 CEILING,DOWN 和 FLOOR 的区别。
UP
是远离零方向(对负数是“向下舍入”,绝对值更大)。CEILING
向正无穷方向(即对负数是“向上舍入”,更接近零),类似于数学中向上取整。
--- 测试数值: 负数 2.55 ---
UP : -2.6
DOWN : -2.5
CEILING : -2.5
FLOOR : -2.6
HALF_UP : -2.6
HALF_DOWN : -2.5