计算机中基本类型float值表示和大小比较问题

通常计算机编程语言中都建议不要比较基本类型float的大小,特别是不要用等号来比较。(BigDecimal等对象类型例外,因为它已经不是采用IEEE 754标准表示法)
举例说明:


十进制小数: 12.75 表示 1*10^1 + 2*10^0 + 7*10^-1 + 5*10^-2  (注:10^1表示10的一次方也就是10,10^-2表示10的-2次方就是是1/100)

用二进制小数表示12.75

二进制小数: 1100.11 = 1*2^3 + 1*2^2 + 1*2^-1 + 1*2^-2  (注:2^3表示2的3次方也就是8,2^-1表示2的-1次方就是1/2,2^-2表示2的-2次方也就是1/4)
用32位 IEEE 754标准表示二进制小数 1100.11(对应于10进制的12.75)


0                 1 0 0 0 0 0 1 0                                10011000000000000000000
1 bit符号位       8 bit浮点偏移量                                  23 bit小数位
0表示正数         此处值为130要减去一个固定值127=3      二进制小数1100.11的第一个1被略去,表示为10011,实际值为(0.10011 + 1)小数点右移3位(浮点偏移)


64位 IEEE 754 标准浮点数的符号位1 bit,浮点偏移位为11 bit,小数位为52 bit 共64 bit


注:1.当浮点偏移位全是0或全是1时表示非规格化数,这个比较特殊,可以不用关注 2.float类型的小数位为23+1 bit,这也是float类型表示10进制数有效数字只有6,7位的原因


而有些小数是无法用IEEE 754浮点表示法精确,表示的,比如10进制数0.1无法用二进制小数精确表示,这和10进制小数无法精确表示1/3道理类似
也就是说单精度(float)的0.1和双精度 (double)的 0.1 在值是不同的(小数位bit数不同,因此精度高后面小数位会多出一截数据)
public static void test()
    {
       float m = (float) 0.1;
       double n = (double) 0.1D;
       if(m == n)
       {
           System.out.println("equal");
       }
       else
       {
           System.out.println("not equal");
       }
    }
结果为not equal
public static void test()
    {
       float m = (float) 0.1;
       float n = (float) 0.1;
       if(m == n)
       {
           System.out.println("equal");
       }
       else
       {
           System.out.println("not equal");
       }
    }
精度相同,结果为equal


但是即使在精度相同的情况下,比较也可能会出问题。


因为在运算过程中会将内存(或高速缓存)中的值加载到CPU浮点寄存器(80 bit扩展精度)中,然后再进入CPU浮点计算单元进行计算,计算结果写回浮点寄存器,然后写回内存(或高速缓存)。从内存到浮点寄存器,浮点数的精度会扩展,从浮点寄存器到内存,浮点数的精度会降低(精度扩展通常没问题,但如果精度降低了,很可能值会发生变化,出现截断),而浮点运算的结果由于下面还要使用所以暂时保存在浮点寄存器中留待下次使用(没有及时写回内存,这是一种优化策略),从而导致数据并不是内存中和内存中的数据比较而是浮点寄存器中的值和内存中的值进行比较,而无论内存中是float类型还是double类型,其精度和浮点寄存器精度都不相同,从而导致比较结果是不相等。


public static void test()
    {
       float m = (float) 0.1;
       float n = (float) 0.1;
       m = m + 1 -1;
       if(m == n)
       {
           System.out.println("equal");
       }
       else
       {
           System.out.println("not equal");
       }
       System.out.println(m);
       System.out.println(n);
    }


精度相同,结果为not equal

转载于:https://my.oschina.net/zuizhuaimaomi/blog/145356

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值