Java:浮点数比较


前言

Java浮点数的比较是开发中经常遇到的问题,但是很容易出错。

本文主要介绍了浮点数比较的正确方法和常见的注意事项。


一、浮点数比较存在误差的原因

简单来说:浮点数比较的时候,精度会丢失,比较结果可能是不对的。

因为浮点数比较的时候会涉及到类型升级(type promotion),而且二进制无法存储一些数字(如3.1415926…)等等的准确值,因此在存储的时候会舍入部分值,也就造成了误差。

同时,float 和 double的精度也不一样,也会因此产生误差。

具体可以参考这篇文章:Java中的浮点数比较 == equals 和 compare

二、浮点数比较的正确方法

1.设置误差范围

原理分析:当两个浮点数之间的差值小于一定限制值时,我们就认为这两个数字相等。

注意:这个限制值,可以根据系统的具体要求和所处环境进行设定,一般是10的-7次方或者10的-14次方。

示例代码如下:

final double limitValue = .000001;
double d1 = .1 * 3;
double d2 = .3;
if(Math.abs(d1-d2) < limitValue) {
    
    
	System.out.println("d1 和 d2 相等");
} else {
    
    
	System.out.println("d1 和 d2 不相等");
}

2.利用BigDemical

不熟悉这个类的朋友可以先去了解一下有关知识:java 中 BigDecimal 详解

注意:BigDemical构造数字时,一定要传入字符串而不是数字:

BigDecimal num=new BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。//推荐使用

原因在于:传入的数字是小数时,本身是个不精确的值,而BigDecimal存储的精确运算,用精确的类型存储不精确的数字就很容易出现问题。

BigDecimal num=new BigDecimal(0.1d) //不推荐使用

示例代码如下:

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.equals(y)) {
    
    
    System.out.println("true");
}

更多内容可以参考Java中的浮点数到底应该怎么比较,才算是最优解?你真的知其然,知其所以然了吗?


三、拓展:Java的0.0和-0.0陷阱

不熟悉的朋友看到这个标题可能会很吃惊:0.0和-0.0不是一样的吗?为什么说是一个陷阱?

原因在于:在Java中,double 区分+ 0.0 和- 0.0 ,也就是说 +0.0 和 -0.0 是两个不同的数字,且+0.0 大于 -0.0。
因为具体存储的时候有一位是符号位,导致+0.0 和 -0.0在内部存储表示的时候并不相同,但是值相同

可以参考:
java浮点数,-0.0小于+0.0
为什么我们在Ruby中有0.0和-0.0?
Java浮点型比较的正确方法

代码示例:

System.out.println(0.0 == -0.0);
System.out.println(Double.compare(0.0, -0.0));
System.out.println(new Double(0.0).equals(new Double(-0.0)));
Map<Double, Integer> map = new HashMap<>();
map.put(0.0, 1);
map.put(-0.0, 2);
System.out.println(map.size());
System.out.println((double)(2-2)/(1-2));
System.out.println((double)(3-3)/(2-1));

输出结果:

true
1
false
2
-0.0
0.0

因此,用HashSet存储的时候,如果key为浮点数,那么一定要注意,0.0和-0.0可以当做两个Key往HashSet插值。

解决办法为:set.add(num+0.0) 这样不会影响具体值,还能克服0.0和-0.0问题。

陷阱分享:【踩坑】Java double 区分正0和负0

总结

本文主要介绍了Java浮点数比较存在误差的原因,介绍了浮点数比较的正确方法。

易错点在于:
(1)BigDemical构造数字时,一定要传入字符串而不是数字
(2)0.0和-0.0问题

希望对大家有用!

猜你喜欢

转载自blog.csdn.net/qq_46119575/article/details/129521129