Java 中的 BigDecimal(浮点类型数据精度丢失的问题)

Java 中的 BigDecimal

1.提出问题

我们都知道浮点型变量在进行计算的时候会出现丢失精度的问题

2.引入测试的demo示例

public class TestBigDecimal  {
	@Test
	public void testDemo() {
		System.out.println(0.05 + 0.01);
		System.out.println(1.0 - 0.42);
		System.out.println(4.015 * 100);
		System.out.println(123.3 / 100);
	}

}

控制台输出:

0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

3.BigDecimal简介

  1. api

    构造器                   描述
      BigDecimal(int)       创建一个具有参数所指定整数值的对象。
      BigDecimal(double)    创建一个具有参数所指定双精度值的对象。
      BigDecimal(long)      创建一个具有参数所指定长整数值的对象。
      BigDecimal(String)    创建一个具有参数所指定以字符串表示的数值的对象。
    
  2. 方法

    方法                    描述
      add(BigDecimal)       BigDecimal对象中的值相加,然后返回这个对象。
      subtract(BigDecimal)  BigDecimal对象中的值相减,然后返回这个对象。
      multiply(BigDecimal)  BigDecimal对象中的值相乘,然后返回这个对象。
      divide(BigDecimal)    BigDecimal对象中的值相除,然后返回这个对象。
      toString()            将BigDecimal对象的数值转换成字符串。
      doubleValue()         将BigDecimal对象中的值以双精度数返回。
      floatValue()          将BigDecimal对象中的值以单精度数返回。
      longValue()           将BigDecimal对象中的值以长整数返回。
      intValue()            将BigDecimal对象中的值以整数返回。
    

4.BigDecimal(String)

问题:

我们在使用BigDecimal时,使用它的BigDecimal(String)构造器创建对象才有意义。其他的如BigDecimal b = new BigDecimal(1)这种,还是会发生精度丢失的问题

  • 错误的代码示例:
	@Test
	public void testBigDecimalString() {
		BigDecimal a = new BigDecimal(1.01);
		BigDecimal b = new BigDecimal(1.02);
		BigDecimal c = new BigDecimal("1.01");
		BigDecimal d = new BigDecimal("1.02");
		System.out.println(a.add(b));
		System.out.println(c.add(d));
	}

控制台输出:

2.0300000000000000266453525910037569701671600341796875
2.03

  • 解释

可见论丢失精度BigDecimal显的更为过分。但是使用Bigdecimal的BigDecimal(String)构造器的变量在进行运算的时候却没有出现这种问题。究其原因计算机组成原理里面都有,它们的编码决定了这样的结果。long可以准确存储19位数字,而double只能准备存储16位数字。double由于有exp位,可以存16位以上的数字,但是需要以低位的不精确作为代价。如果需要高于19位数字的精确存储,则必须用BigInteger来保存,当然会牺牲一些性能。所以我们一般使用BigDecimal来解决商业运算上丢失精度的问题的时候,声明BigDecimal对象的时候一定要使用它构造参数为String的类型的构造器。

5.正确运用BigDecimal这个工具类

说明:

在一般开发过程中,我们数据库中存储的数据都是float和double类型的。在进行拿来拿去运算的时候还需要不断的转化,这样十分的不方便。这里我写了一个工具类:

  • 代码:

    // 封装好的工具类
    //该工具类提供了double类型的基本的加减乘除运算。直接调用即可
    import java.math.BigDecimal;
    
    public class BigDecimalUtil {
    
        private BigDecimalUtil() {
    
        }
    
        public static BigDecimal add(double v1, double v2) {// v1 + v2
            BigDecimal b1 = new BigDecimal(Double.toString(v1));
            BigDecimal b2 = new BigDecimal(Double.toString(v2));
            return b1.add(b2);
        }
    
        public static BigDecimal sub(double v1, double v2) {
            BigDecimal b1 = new BigDecimal(Double.toString(v1));
            BigDecimal b2 = new BigDecimal(Double.toString(v2));
            return b1.subtract(b2);
        }
    
        public static BigDecimal mul(double v1, double v2) {
            BigDecimal b1 = new BigDecimal(Double.toString(v1));
            BigDecimal b2 = new BigDecimal(Double.toString(v2));
            return b1.multiply(b2);
        }
    
        public static BigDecimal div(double v1, double v2) {
            BigDecimal b1 = new BigDecimal(Double.toString(v1));
            BigDecimal b2 = new BigDecimal(Double.toString(v2));
            // 2 = 保留小数点后两位   ROUND_HALF_UP = 四舍五入
            return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);// 应对除不尽的情况
        }
    }
    

    该工具类提供了double类型的基本的加减乘除运算。直接调用即可

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值