浮点型包装类(Float、Double、BigDecimal)的使用与解析

目录

一、使用

二、解析


一、使用

在Java程序设计中,浮点数处理存在失真(丢失精度)问题,例如:

out.println(0.1 + 0.2);    //输出0.30000000000000004
out.println(0.1 * 0.2);    //输出0.020000000000000004

double num1 = 2.8f;
out.println(num1);        //输出2.799999952316284

double a = 0.7;
out.println(new BigDecimal(a));    //输出0.6999999999999999555910790149937383830547332763671875

因此,在处理精确度和准确度要求都非常高的数据时,不宜直接使用单精度和双精度数据类型,通常应用BigDecimal(String val)来声明存储浮点数的变量,并用BigDecimal中对应的方法来计算,最后可通过其BigDecimal中的toString()方法获得对应的值

二、解析

为什么在对浮点数进行存储、计算、类型转换时会出现失真呢?其核心是因小数转二进制和浮点数的存储机制引起的。为什么用BigDecimal(String val)不会出现失真现象呢?这与BigDecimal的处理机制有关系。

1、浮点数存储机制

计算机先将数值转换成二进制并用科学计数法表示,然后根据类型存储0、1代码。

单精度浮点数存储格式:

1bit8bits23bits

双精度浮点数存储格式:

1bit11bits52bits

在上面两个表格中,第一列是符号位,第二列是存储指数的位数,第三列是存储尾数的位数(要减1)。因此,当单精度浮点数的尾数超过24位时,后面的二进制位数将丢失;双精度浮点数的尾数超过53位时,后面的二进制位数将丢失。

注意:要想具体了解浮点数的存储机制,请参考网上的其他资料,在此只说明造成失真的原因,因此不赘述。

2、小数转二进制的问题

小数转二进制是用该数乘以2,并取乘积的整数部分,直到乘积为0。

如:0.1转换成为二进制位0.0001100110011...,0.2转换成二进制为0. 001100110011...

以上两数转换成二进制时都出现了无限循环,因此,表示成科学计数法时,其尾数会超出浮点数存储要求的尾数,超出部分将会丢失,因此产生失真

3、BigDecimal的核心机制

用intCompact(声明形式:private final transient long intCompact)变量存储浮点数的有效数值,用scale(声明形式:private final int scale)变量存储浮点数的小数位数。如:

555.6666:intCompact变量会存入5556666,scale变量会存入4。

计算时,用对应的intCompact值参与运算,即存储和运算都使用了long型,所以不会失真。

要想得到真实的数字,只需调用toString方法即可,此方法会以字符串处理的方式,在intCompact表示的数值中加入小数点并返回

特别注意:为了不失真,尽量不使用public BigDecimal(double val,...)构造方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值