浮点数处理问题
yuankaiqiang Lv5

关于浮点数处理问题,BigDecimal的精度问题,BigDecimal增删查改操作,参考阿里巴巴Java开发手册规范处理


浮点数比较问题

浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用equals来判断。

问题:可以发现这两句都没有执行

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
float a = 1.0F - 0.9F;
float b = 0.9F - 0.8F;
if (a == b) {
System.out.println("未执行");
}
Float x = Float.valueOf(a);
Float y = Float.valueOf(b);
if (x.equals(y)) {
System.out.println("未执行");
}
}

这里阿里巴巴JAVA开发手册 ^1中也有提到

image-20210715142952399

解决

  1. 指定一个误差范围,两个浮点数的差值在此范围之内,则认为是相等的

    1
    2
    3
    4
    5
    6
    float a =1.0F-0.9F;
    float b =0.9F-0.8F;
    float diff =1e-6F;
    if(Math.abs(a -b)<diff){
    System.out.println("执行");
    }
  2. 使用BigDecimal来定义值,再进行浮点数的运算操作(推荐使用

    1
    2
    3
    4
    5
    6
    7
    8
    BigDecimal a = new BigDecimal("1.0");
    BigDecimal b = new BigDecimal("0.9");
    BigDecimal c = new BigDecimal("0.8");
    BigDecimal x = a.subtract(b);
    BigDecimal y = b.subtract(c);
    if (x.compareTo(y) == 0) {
    System.out.println("执行");
    }

    比较时候使用compareTo进行比较,equals()方法会比较值和精度(1.0与1.00返回结果为false),而compareTo()则会忽略精度,使用下面代码进行测试发现只有compareTo执行了。

    1
    2
    3
    4
    5
    6
    7
    8
    BigDecimal x = new BigDecimal("0.1");
    BigDecimal y = new BigDecimal("0.10");
    if(x.equals(y)) {
    System.out.println("未执行!");
    }
    if(x.compareTo(y) == 0) {
    System.out.println("执行!");
    }

BigDecimal初始化

初始化时应该使用字符串的形式进行初始化定义,对比一下他们的区别

1
2
3
4
BigDecimal a = new BigDecimal(0.1F); 
BigDecimal b = new BigDecimal("0.1");
System.out.println(a);
System.out.println(b);
image-20210715144946836

两种方式定义的值不一样,BigDecimal(double)存在精度损失风险,这里阿里巴巴Java开发手册 ^1中也有提及

image-20210715145241058

BigDecimal增删查改操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
BigDecimal a = new BigDecimal("0.123");
BigDecimal b = new BigDecimal("0.987");
BigDecimal c = new BigDecimal("-0.555");

// 加
BigDecimal add = a.add(b);
// 减
BigDecimal subtract = a.subtract(b);
// 乘
BigDecimal multiply = a.multiply(b);
// 除,设置保留的小数点位数与四舍五入
BigDecimal divide = a.divide(b, 20, BigDecimal.ROUND_HALF_UP);
// 绝对值
BigDecimal abs = c.abs();

System.out.println(add);
System.out.println(subtract);
System.out.println(multiply);
System.out.println(divide);
System.out.println(abs);
}

除法中的第二个参数是设置保留的小数点位数,第三个参数是设置如何进行四舍五入操作,阅读源码可知就是我们的平时使用的大于等于0.5时候就进一位。

image-20210715151451175

运行结果

image-20210715151042861

BigDecimal还有一些其它操作,可以去操作尝试下

阿里JAVA开发手册地址

手册阿里云盘链接:https://www.aliyundrive.com/s/MEtW4t5DdGh

 评论