首页 > 其他分享 >阿里巴巴为什么建议使用BigDecimal进行浮点数运算

阿里巴巴为什么建议使用BigDecimal进行浮点数运算

时间:2023-03-26 11:34:09浏览次数:38  
标签:return BigDecimal 浮点数 Number value values result 阿里巴巴

本文先引入一个例子,星期天你和女朋友去逛街,看到一家奶茶店。女朋友想喝奶茶了,你就去买了杯奶茶,然后你问了一下价格。店员说奶茶0.9元一杯。然后你给了1元钱。这个时候你忽然问了一下女友。服务员该找我们多少钱呢?女友说你个小傻瓜当然是0.1元啊。作为一个”严谨“的程序猿,这时你拿起电脑写了个简单计算如下:

看到计算结果不是0.1这个时候你有点慌了,女朋友怎么会错呢?但是你没有犹豫女朋友说的怎么会错呢,女朋友说的一定是对的。一定是电脑计算错了,然后你毫不犹豫把电脑扔了。说了一句对对对该找0.1元。【PS奶茶目前当然不可能1元钱,本文为了演示计算效果所以定义奶茶1元,因为不是所有的浮点运算都会有这样的问题】。

千万别小看这些一点点的计算误差,假如我说假如全国人民一人送你0.1元你能实现财富自由了【呸,别做白日梦了好好搬砖去吧】

好了聊文章的主题BigDecimal这个知识点,这个知识点应该很多人都知道了,我感觉很有有用就聊一下。阿里巴巴开发手册中提到:

使用BigDecimal来定义值,再进行浮点数的运算操作。

 

注意:BigDecimal(double)存在精度损失的风险,在精确计算或比较的场景中可能会导致业务逻辑异常。如:BigDecimal g = new BigDecimal(0.1f)。实际存储的值为:0.10000000149011611938 。

      float a = 1.0f -0.9f;
        float b = 0.9f-0.8f ;
        System.out.println(a);
        System.out.println(b);
        System.out.println(a==b);

为什么浮点数 float 或 double 运算的时候会有精度丢失的风险呢?

这个和计算机保存浮点数的机制有很大关系。我们知道计算机是二进制的,而且计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。

那怎么解决精度丢失的问题呢?那就是本文要说的BigDecimal。用它可以实现对浮点的计算,解决精度丢失的问题。如下用差不多相同的代码结果就是对的【PS一定要记住女朋友说的就是对的就是0.1】。

BigDecimal创建方法,请先看注意事项:

阿里官方:【强制】禁止使用构造方法BigDecimal(double)的方式把double值转换为BigDecimal对象

  正确的创建方法:优先推荐入参为String的构造方法,或者使用BigDecimal的valueOf方法,此方法内部其实执行了Double的toString。而Double的toString按double实际能表达的精度对尾数进行了拦截。如下推荐使用:

BigDecimal a = new BigDecimal("0.1"); 

BigDecimal  b = BigDecimal.valueOf(0.1);

 

开发中用到计算也就是加减乘除,BigDecimal中相关方法如下:

add 方法用于将两个 BigDecimal 对象相加。subtract 方法用于将两个 BigDecimal 对象相减。multiply 方法用于将两个 BigDecimal 对象相乘,divide 方法用于将两个 BigDecimal 对象相除。

这里需要注意的是,在我们使用 divide 方法的时候尽量使用 3 个参数方法。其中 scale 表示要保留几位小数,roundingMode 代表保留规则。具体可以看源码,源码中介绍的很清楚了,并且给了各种例子如下:

大小的比较

a.compareTo(b) : 返回 -1 说明 a 小于 b,0 说明a 等于 b , 1 说明 a 大于 b。用法如下:

注意:BigDecimal的比较不能使用equals进行比较【原因还是因为精度的问题】,一定要使用compareTo比较,如下:

BigDecilmal计算相关的工具类。

add方法:

public static BigDecimal add(Number v1, Number v2) {
        return add(new Number[]{v1, v2});
    }
    public static BigDecimal add(Number... values) {
        if (ArrayUtil.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        Number value = values[0];
        BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (null != value) {
                result = result.add(new BigDecimal(value.toString()));
            }
        }
        return result;
    }

substract方法:

public static BigDecimal sub(Number v1, Number v2) {
        return sub(new Number[]{v1, v2});
    }
    public static BigDecimal sub(Number... values) {
        if (ArrayUtil.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        Number value = values[0];
        BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (null != value) {
                result = result.subtract(new BigDecimal(value.toString()));
            }
        }
        return result;
    }

multiply 乘法:

public static BigDecimal mul(Number v1, Number v2) {
        return mul(new Number[]{v1, v2});
    }
    public static BigDecimal mul(Number... values) {
        if (ArrayUtil.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        Number value = values[0];
        BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            result = result.multiply(new BigDecimal(null == value ? "0" : value.toString()));
        }
        return result;
    }

divide 除法:

public static BigDecimal div(BigDecimal v1, BigDecimal v2,Integer scale,RoundingMode roundingMode) {
        if (null == v1) {
            return BigDecimal.ZERO;
        }
        if (scale < 0) {
            scale = -scale;
        }
        return v1.divide(v2, scale, roundingMode);
    }

谢谢点赞,也欢迎你分享给其他的开发者,让更多的人知道。当然也欢迎未关注的小伙伴关注。

 

  11

标签:return,BigDecimal,浮点数,Number,value,values,result,阿里巴巴
From: https://www.cnblogs.com/scott1102/p/17257865.html

相关文章

  • 浮点数的定点化
    例题1、【大疆】对12.918做无损定点化,需要的最小位宽是多少位?位宽选择11位时的量化误差是多少?A13位,0.0118B12位,0.0118C13位,0.0039D12位,0.0039分析:(1)整数12......
  • 计算机定点数和浮点数
    一、概念1.定点数定点数表示法约定==计算机中所有数据的小数点位置固定==,其中,将小数点的位置固定在数据的最高位之前(或符号位之后)的数据表示称为定点小数,而将小数点固定......
  • BigDecimal stripTrailingZeros() 科学计数法问题
    问题//打印结果为科学计数法:5E+1System.out.println(newBigDecimal("50.000").stripTrailingZeros().toString());解决//打印结果为:50System.out.println(newB......
  • [嵌入式RTOS]记录一下因浮点数转为字符串导致精度损失所踩的坑
    1.起因:工作中对接平台需要将设备的GPS数据传给平台,但是平台采用的不是回调函数将数据直接作为参数返回而是格式化的字符串命令,所以需要将double类型的gps数据格式化输出到......
  • BigDecimal金额值和0做差值比较
    #可能我们有时候做金额差的时候,会查看是否等于0#比如我的入账金额和出账金额是大于0还是小于0#参考案例BigDecimalnum=newBigDecimal("18");inti=num.compareTo(Big......
  • BigDecimal运算
    importjava.math.BigDecimal;/***由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精*确的浮点数运算,包括加减乘除和四舍五入。*/publicclass......
  • BigInteger和BigDecimal18
    BigInteger在Java中,由CPU原生提供的整型最大范围是64位​​long​​型整数。使用​​long​​型整数可以直接通过CPU指令进行计算,速度非常快。如果我们使用的整数范围超过了......
  • 浮点数编码原理
    1前言​计算机中浮点数的编码,由美国加州大学的WilliamKahan教授于1985年设计,后被IEEE借鉴,制定出IEEE浮点标准。​浮点数在计算机中的二进制编码由符号......
  • BigDecimal一定不会丢失精度吗?
    Java中float的精度为6-7位有效数字。double的精度为15-16位。我们在使用BigDecimal时,使用它的BigDecimal(String)构造器创建对象才有意义。其他的如BigDecimalb=new......
  • java进阶 -bigDecimal 41
        packagecom.cyjt97.BD;importjava.math.BigDecimal;importjava.math.RoundingMode;//BigDecimal解决小数不精准问题publicclassday{public......