zoukankan      html  css  js  c++  java
  • Java中浮点数的精度问题 【转】

    当您在计算Money的时候,请看好了!!!要不损失了别后悔!!!

    现象1

        public static void main(String[] args) {

           System.out.println(0.030*100);//输出3.0

           System.out.println(0.031*100);//输出3.1

           System.out.println(0.032*100);//输出3.2

           System.out.println(0.033*100);//输出3.3000000000000003

           System.out.println(0.034*100);//输出3.4000000000000004

           System.out.println(0.035*100);//输出3.5000000000000004

           System.out.println(0.036*100);//输出3.5999999999999996

           System.out.println(0.037*100);//输出3.6999999999999997

           System.out.println(0.038*100);//输出3.8

           System.out.println(0.039*100);//输出3.9

        }

    现象2

        public static void main(String[] args) {

           BigDecimal b1 = new BigDecimal("0.236");

           BigDecimal b2 = new BigDecimal(0.236);

           System.out.println(b1);//输出0.236

           System.out.println(b2);//输出0.2359999999999999875655021241982467472553253173828125

    }

    描述:

    当我们使用一些“特殊的数字”进行运算时,或者调用BigDecimal中new BigDecimal(double val)进行构造的时候,将得到意想不到的结果。

    原因:

    Java中,浮点类型是依据IEEE754标准的。IEEE754定义了32位和64位双精度两种浮点二进制小数标准。采用二进制表示double,float等浮点数是不准确的。

    同时BigDecimal的API声明,建议使用new BigDecimal(String val)进行构造,使用new BigDecimal(double val)进行构造的时候,将得到意想不到的结果(The results of this constructor can be somewhat unpredictable)。

    解决办法(以0.236*100 = 23.599999999999998为例)

    1、 通过String结合BigDecimal来转换。

           String val = "0.236";

           //使用new BigDecimal(String val)进行构造

           BigDecimal a = new BigDecimal(""+val);

           BigDecimal b = new BigDecimal(""+100);

           //小数的位数与构造参数的位数一致

           System.out.println(a.multiply(b));//输出23.600

    2、  通过移位结合BigDecimal来转换

           String val = "0.236";

           //使用new BigDecimal(String val)进行构造

           BigDecimal a = new BigDecimal(""+val);

           //向右移两位

           a = a.movePointRight(2);

           System.out.println(a);//输出23.6

    3、  使用保留小数位的方法来转换

           double result = 0.236*100;

           System.out.println(result);//输出23.599999999999998

           //计算保留result小数点后四位,以此类推,1后面几个零就是保留小数点后几位数.如下保留两位小数

           result = (double)(Math.round(result*100)/100.0)            ;

           System.out.println(result);//输出23.6

    4、 使用DecimalFormat来确定小数点后位数

           double val = 0.236*100;

           //保留小数点后两位,若保留三位为"#.000"

           DecimalFormat df = new DecimalFormat("#.00");

           String str = df.format(val);

           System.out.println(Double.valueOf(str));//输出23.6

    5、-----方法很多,一个即可

    心得:

    处理这样的精度问题方法很多,只要不是直接采用浮点数进行计算就行。

    附加:

    IEEE 754用科学记数法以底数为2的小数来表示浮点数。32位浮点数用1位表示数字的符号,用8位来表示指数,用23位来表示尾数,即小数部分。作为有符号整数的指数可以有正负之分。小数部分用二进制(底数2)小数来表示。对于64位双精度浮点数,用1位表示数字的符号,用11位表示指数,52位表示尾数。如下两个图来表示:

    float(32位):

    1位,符号位

    幂(8位)

    尾数(32位)

    double(64位):

    1位,符号位

    幂(11位)

    尾数(52位)

    都是分为三个部分:

    (1)一个单独的符号位s直接编码符号s。

    (2)k位的幂指数E,移码表示

    (3)n位的小数,原码表示

  • 相关阅读:
    024.Zabbix告警等级机制
    023.Zabbix自定义(邮箱)脚本告警-02
    022.Zabbix自定义(邮箱)脚本告警01
    021.Zabbix的邮件告警-01
    020.Zabbix的Actions配置
    019.Zabbix的Trigger及相关函数
    018.Zabbix维护时间和模板导入
    017.Zabbix宏介绍
    016.Zabbix聚合监控
    015.Zabbix的日志监控配置
  • 原文地址:https://www.cnblogs.com/disneyland/p/4541798.html
Copyright © 2011-2022 走看看