java基础-浮点数陷阱

计算机的数值采用的是二进制形式存储。
根据IEEE754标准,
单精度浮点数为32位:

- sign exponent fraction
位数 1 bit 8 bit 23 bit
编号(右起) 31 30 ~ 23 22 ~ 0

双精度浮点数为64位:

- sign exponent fraction
位数 1 bit 11 bit 52 bit
编号 63 62 ~ 52 51 ~ 0

0.99用的有效数字部分(fraction):
        0.99 * 2 = 1+0.98 --> 1
        0.98 * 2 = 1+ 0.96 --> 1
        0.96 * 2 = 1+0.92 -- >1
        0.92 * 2 = 1+0.84 -- >1...............

所以计算机二进制无法精确表示浮点数,精度有损失。示例代码如下:

public class FloatTrap {
    public static void main(String[] args) {
        double a = 1;
        double b = 0.99;
        System.out.println(a - b);
    }
}//:output
//0.010000000000000009

java的浮点类型有double(双精度)和float(单精度)。对于精确的浮点数运算可以使用java.math.BigDecimal类,但是这样依然会有精度损失。最佳的方法是使用string转double或者float,这样是没有精度损失的。
使用BigDecimal类示例

import java.math.BigDecimal;

public class Main {

    public static void main(String[] args) {
        double a = 2.0;
        double b = 1.9;
        System.out.println(2.0 - 1.9);
        System.out.println(Main.round(Main.subtract(a,b)));
    }

    /*精确的浮点数计算*/

    private static double subtract(double m, double n){

        BigDecimal tm = new BigDecimal(Double.toString(m));
        BigDecimal tn = new BigDecimal(Double.toString(n));
        return tm.subtract(tn).doubleValue();

    }

    /*四舍五入保留*/
    private static double round(double target){
        BigDecimal tmp = new BigDecimal(Double.toString(target));
        BigDecimal one = new BigDecimal(Double.toString(1.0));

        return tmp.divide(one,BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    private static double div(double tm,double tn){
        BigDecimal tempM = new BigDecimal(Double.toString(tm));
        BigDecimal tempN = new BigDecimal(Double.toString(tn));
        return tempM.divide(tempN,10, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    private static double add(double tm, double tn){
        BigDecimal tempM = new BigDecimal(Double.toString(tm));
        BigDecimal tempN = new BigDecimal(Double.toString(tn));
        return tempM.add(tempN).doubleValue();

    }


}

你可能感兴趣的:(java基础-浮点数陷阱)