double类型(浮点数)是否相等的判断方法

java基础 同时被 2 个专栏收录
102 篇文章 1 订阅
69 篇文章 0 订阅

浮点数不精确

计算机内部无法用二进制的小数来精确的表达。

public class Tesz {
    public static void main(String[] args) {

        double a = 0.1;
        float c = 0.1f;
        System.out.println(a==c);//输出false
    }
}
  • 如果运算符任意一方的类型为double,则另一方会转换为double
  • 否则,如果运算符任意一方的类型为float,则另一方会转换为float
  • 否则,如果运算符任意一方的类型为long,则另一方会转换为long
  • 否则,两边都会转换为int

根据IEEE 754,单精度的float是32位,双精度的double为64位

第一部分(s)为符号位,第二部分(exponent)为指数位,第三部分(mantissa)为基数部分。 这是科学计数法的二进制表示。

  •  比如像3.1415926.。。。  或者无限无限循环小数,就会将不能标识的部分舍掉。
  • 二进制无法精确表示浮点数

二进制为什么无法精确表示浮点数

单精度浮点数0.1表示成二进制

System.out.println(Integer.toBinaryString(Float.floatToIntBits(0.1f)));  

结果是:111101110011001100110011001101
双精度的浮点数0.1的二进制

System.out.println(Long.toBinaryString(Double.doubleToLongBits(0.1d)));  

结果是:11111110111001100110011001100110011001100110011001100110011010
float转换后的double的值已经和直接赋值的double的值比较

System.out.println(Long.toBinaryString(Double.doubleToLongBits(0.1f)));  

结果是:11111110111001100110011001100110100000000000000000000000000000

很明显不一样

二进制小数的表达形式

根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:

 

 

  (1)(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。

  (2)M表示有效数字,大于等于1,小于2。

  (3)2^E表示指数位。

举个例子 用二进制表达十进制的 0.2 

0.01 = 1/4 = 0.25 ,太大

0.001 =1/8 = 0.125 , 又太小

0.0011 = 1/8 + 1/16 = 0.1875 , 逼近0.2了

0.00111 = 1/8 + 1/16 + 1/32 = 0.21875 , 又大了

0.001101 = 1/8+ 1/16 + 1/64 = 0.203125 还是大

0.0011001 = 1/8 + 1/16 + 1/128 = 0.1953125 这结果不错

0.00110011 = 1/8+1/16+1/128+1/256 = 0.19921875

.......................................................

第一种方法:转换成字符串

如果要比较的两个浮点数数据的字符串精度相等,可以将数据转换成string然后借助string的equals方法来间接实现比较两个double数据是否相等。注意这种方法只适用于比较精度相同的数据,并且是只用用于比较是否相等的情况下,不能用来判断大小。

Float.toString(453.2348f).equals(Float.toString(0.342f))

Double.toString(0.8456d).equals(Float.toString(0.242f))

第二种方法:使用sun提供的Double.doubleToLongBits()方法

该方法可以将double转换成long型数据,从而可以使double按照long的方法(<, >, ==)判断是否大小和是否相等。

Double.doubleToLongBits(0.01) == Double.doubleToLongBits(0.01) 
Double.doubleToLongBits(0.02) > Double.doubleToLongBits(0.01) 
Double.doubleToLongBits(0.02) < Double.doubleToLongBits(0.01)

第三种方法:误差内比较

对于double类型,比如double d1=0.0000001,double d2=0d 当判断两个数据d1和d2是否相等的时候,一般不直接使用

if(d1==d2)

    ...

第四种办法:BigDecimal类型

double a = 0.001; 
double b = 0.0011; 
BigDecimal data1 = new BigDecimal(a); 
BigDecimal data2 = new BigDecimal(b); 
data1.compareTo(data2) 
非整型数,运算由于精度问题,可能会有误差,建议使用BigDecimal类型!

反例1:用equals方法可以吗

Double a = Double.valueOf("0.0");  
Double b = Double.valueOf("-0.0");  
System.out.println(a.equals(b));  

false

Double a = Math.sqrt(-1.0);  
Double b = 0.0d / 0.0d;  
Double c = a + 200.0d;  
Double d = b + 1.0d;  
System.out.println(a.equals(b));  
System.out.println(b.equals(c));  
System.out.println(c.equals(d));  

true
true
true

equals方法是比较2个对象是否等值,而不是对象的值是否相等

反例2:用compareTo方法可以吗

public static void main(String[] args) {

        Double a = Double.valueOf("0.0");
        Double b = Double.valueOf("-0.0");
        System.out.println(a.compareTo(b));

        //1

        Double a1 = Math.sqrt(-1.0);
        Double b1 = 0.0d / 0.0d;
        Double c1 = a1 + 200.0d;
        Double d1 = b1 + 1.0d;
        System.out.println(a1.compareTo(b1));
        System.out.println(b1.compareTo(c1));
        System.out.println(c1.compareTo(d1));

        //0
        //0
        //0
    }

 a和b表示为NaN(Not a Number) ,并不是数字,无法比较。

总结

在进行浮点数比较的时候,主要需要考虑3个因素

  • NaN
  • 无穷大/无穷小
  • 舍入误差

所以,要比较浮点数是否相等,需要做的事情是:

  • 排除NaN和无穷
  • 在精度范围内进行比较

参考连接

https://blog.csdn.net/renwotao2009/article/details/51637163

http://en.wikipedia.org/wiki/Floating_point

https://blog.csdn.net/wcxiaoych/article/details/42806313#

https://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html

本公众号分享自己从程序员小白到经历春招秋招斩获10几个offer的面试笔试经验,其中包括【Java】、【操作系统】、【计算机网络】、【设计模式】、【数据结构与算法】、【大厂面经】、【数据库】期待你加入!!!

1.计算机网络----三次握手四次挥手
2.梦想成真-----项目自我介绍

3.你们要的设计模式来了

4.一字一句教你面试“个人简介”

5.接近30场面试分享

6.你们要的免费书来了

  • 2
    点赞
  • 3
    评论
  • 12
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 撸撸猫 设计师:马嘣嘣 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值