java中为什么小数运算丢失精度,丢失精度却为何能精确输出

564 阅读2分钟

为什么丢失精度

计算机运用二进制存储数据
十进制小数转二进制小数的办法

对小数点后的数乘以2,会得到一个成果,取成果的整数部分(不是1便是0),然后再用小数部分再乘以2,再取成果的整数部分……以此类推,直到小数部分为0或许位数现已够了。次序取每次运算得到的整数部分,即为转化后的小数部分。
演示:
0.125 ×2=0.25 …0
0.25×2=0.5…0
0.5×2=1.0…1
即 0.125的二进制表明为小数部分为0.001

其实咱们能够看出,这种办法实质上便是用1/2,1/4,8/1…来组合加出咱们要转化的数据值,但明显不是一切的数都能够组合出来的。如0.1。
0.1×2=0.2 …0
0.2×2=0.4 …0
0.4×2=0.8 …0
0.8×2=1.6…1
0.6×2=1.2…1
0.2×2=0.4…0

从上述能够看出,这是个无限小数,所以在这种情况下float、double只能舍去一些位。
但为什么System.out.println(2.00f-1.10f);得出的结果是0.9呢。因为float精度没有double精度那么大,小数部分0.1二进制表示被舍去的比较多

为什么能精确输出

public static void main(String[] args) {
        float a = 0.7f;
        float b = 0.69999996f;
        float c = 0.70000001f;
 
        System.out.println(a);  //0.7
        System.out.println(b);  //0.7
        System.out.println(c);  //0.7
 
        System.out.println(Integer.toUnsignedString(Float.floatToIntBits(a), 16));//3f333333
        System.out.println(Integer.toUnsignedString(Float.floatToIntBits(b), 16));//3f333333
        System.out.println(Integer.toUnsignedString(Float.floatToIntBits(c), 16));//3f333333
 
        System.out.println(a==b); //true
        System.out.println(a==c); //true
 
 
        float d = 0.70000002f;
        System.out.println(d);    //0.70000005
        System.out.println(Integer.toUnsignedString(Float.floatToIntBits(d), 16));//3f333334
 
    }

java中小数的存储形式固定,例如在java中0.7的表示形式就是3f333333,这个就是0.7。不管你开始给变量赋值是用a, b 还是c, 他们在内存中的表示是一样的,所以输出都是0.7。所以根本就不存在为什么可以输出0.7的问题,因为是0.7肯定要输出0.7。只有在计算的时候才会把3f333333换算成大约是0.699999988,