当前位置:首页 > Java技术 > BigDecimal 基本使用

BigDecimal 基本使用

2022年09月17日 10:17:31Java技术4

BigDecimal 是java小数操作的一个专有类,在电商、金融行业 存储跟金额有关的字段

java里面明明已经有了,float,double这种精度的小数,为什么还需要BigDecimal呢?
这难道不是多余吗?

接下来看一个例子:

@Test
public void testDoubleSimple() {
    double a = 3;
    double b = 10;
    double c = a / b;
    System.out.println(c);
}

控制台输出:0.3

在小数操作中,我们通常希望能有多种自由的定义方式。

例如在不同的场景可能需要返回: 0.3, 0.4, 0.333 不同精度,在不同的精度进位时希望能自主控制

这个时候,就轮到BigDecimal出场了

加减乘除

首先来一段最简单的加减乘除

@Test
 public void testDecimalSimple() {
     BigDecimal a = new BigDecimal(5);
     BigDecimal b = new BigDecimal(40);
     BigDecimal add = a.add(b);
     BigDecimal subtract = a.subtract(b);
     BigDecimal multiply = a.multiply(b);
     BigDecimal divide = a.divide(b);
     System.out.println("add:" + add);
     System.out.println("subtract:" + subtract);
     System.out.println("multiply:" + multiply);
     System.out.println("divide:" + divide);
 }

控制台输出内容如下:

add:45
subtract:-35
multiply:200
divide:0.125

在了解了BigDecimal基本内容后,在去深入的去使用它的精度

精度控制

精度有7种模式,举例如下

@Test
public void testRound() {
     // 正无穷大方向取整
     System.out.println("celling:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.CEILING)));
     // 负无穷大方向取整
     System.out.println("floor:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.FLOOR)));
     //向 0 的方向取整
     System.out.println("down a:" + new BigDecimal(0.121, new MathContext(2, RoundingMode.DOWN)));
     System.out.println("down b:" + new BigDecimal(-0.129, new MathContext(2, RoundingMode.DOWN)));
     // 正数向正无穷大取整,负数向负无穷大取整
     System.out.println("up a:" + new BigDecimal(0.121, new MathContext(2, RoundingMode.UP)));
     System.out.println("up b:" + new BigDecimal(-0.129, new MathContext(2, RoundingMode.UP)));
     /**
      * 5,6,7,8,9 向上取整
      * 1,2,3,4 向下取整
      *
      * 常用的4舍5入
      */
     System.out.println("half up:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.HALF_UP)));
     /**
      *  6,7,8,9 向上取整
      *  1,2,3,4,5 向下取整
      *
      *  5 向下取整
      */
     System.out.println("half down:" + new BigDecimal(0.125, new MathContext(2, RoundingMode.HALF_DOWN)));

     /**
      * 小数位是5时,判断整数部分是奇数就进位
      * 1,2,3,4,  舍弃
      * 6,7,8,9,  进位
      */
     System.out.println("odd a:" + new BigDecimal(5.4, new MathContext(1, RoundingMode.HALF_EVEN)));
     System.out.println("odd b:" + new BigDecimal(5.5, new MathContext(1, RoundingMode.HALF_EVEN)));
     /**
      * 小数位是5时,判断整数部分是偶数就舍弃
      * 1,2,3,4,  舍弃
      * 6,7,8,9,  进位
      */
     System.out.println("even a:" + new BigDecimal(6.5, new MathContext(1, RoundingMode.HALF_EVEN)));
     System.out.println("even b:" + new BigDecimal(6.6, new MathContext(1, RoundingMode.HALF_EVEN)));
 }

控制台输出内容如下

celling:0.13
floor:0.12
down a:0.12
down b:-0.12
up a:0.13
up b:-0.13
half up:0.13
half down:0.12
odd a:5
odd b:6
even a:6
even b:7

在 RoundingMode.XXXXX 类型的源码注释上面,有更加详细的例子,可以看到是怎么舍入的

除法特写

我认为在电商,金融领域中,用BigDecimal最重要的原因有两个:
1. 精度准确
2. 除法运算支持好

所以一定要对除法做深入的了解,做项目的时候,才能不会对这些类型感到疑惑

    @Test
    public void testDecimalDivide() {
        BigDecimal a = new BigDecimal(5.4);
        BigDecimal b = new BigDecimal(3.1);
        BigDecimal divide = a.divide(b);
        System.out.println("divide:" + divide);
    }

出现异常:
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

明明刚刚还好好的,怎么现在出了事?

那是因为 5.43.1都是double类型转换的 BigDecimal。

实际上5.4在内存中可能是 5.40000003321546546 的内容。导致BigDecimal内部精度计算的时候,发生错误

这个错误是因为没有指定精度导致的,我们只要指定了结果的精度,就可以避免这个问题。

推荐做法

    @Test
    public void testDecimalStandDivide() {
        BigDecimal a = new BigDecimal(5.4);
        BigDecimal b = new BigDecimal(3.1);
        // 保留几位小数
        int scale = 2;
        // 重点:务必是3个参数
        BigDecimal divide = a.divide(b,scale,RoundingMode.HALF_UP);
        System.out.println("divide:" + divide);

    }

控制台输出:divide:1.74

我们额外传入第二个参数:保留的小数,指定了结果的精度,就可以避免出现这种问题。

所以我们日常用BigDecimal做除法运算的时候,务必写成推荐的形式。避免出现了异常,自己还莫名其妙

默认除法精度

在文章的开头的除法,是用整数转成BigDecimal, 保留的3为小数。 那默认情况下会精确到几位呢?

在跟进到divide函数内部时,发现了构造MathContext的部分内容:

 MathContext mc = new MathContext( (int)Math.min(this.precision() +
                                                            (long)Math.ceil(10.0*divisor.precision()/3.0),
                                                            Integer.MAX_VALUE),
                                              RoundingMode.UNNECESSARY);

整数 12345 的precision 是5
整数 332 的precision 是 3
小数5.4 的precision可能是 5.40000065464698656565454454555 的长度。 值不固定

根据MathContext的第一个参数的计算方式得到默认除法精度:
1. 当被除数为:0x1 最低精度5
2. 当被除数为:0xFFFFFFFF 最高精度36

总结

BigDecimal 精度描述:

模式 描述
CEILING 正无穷大方向取整
FLOOR 负无穷大方向取整
DOWN 向 0 的方向取整
UP 正数向正无穷大取整,负数向负无穷大取整
HALF_UP 5,6,7,8,9 向上取整、 1,2,3,4 向下取整、 常用的4舍5入
HALF_DOWN 6,7,8,9 向上取整 1,2,3,4,5 向下取整
HALF_EVEN 小数位是5时,判断整数部分是奇数就进位、 小数位是5时,判断整数部分是偶数就舍弃、 1,2,3,4, 舍弃、 6,7,8,9, 进位

作者:东平王北星
来源链接:https://blog.csdn.net/mz4138/article/details/82708815

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/42532.html

标签: BigDecimal
分享给朋友:

“BigDecimal 基本使用” 的相关文章

Java中,String类型转换BigDecimal类型

public static void main(String[] args) {               String str="1.2034";       &nb...

Java BigDecimal详解

Java BigDecimal详解

引言   float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。但是,商业计算往往要求结果精确,这时候Big...

Springmvc bigdecimal精度丢失问题

一、在实体使用注解的方式 @JsonSerialize(using=ToStringSerializer.class) private BigDecimal minPrice = new BigDecimal(0); 二、使用配置方式 1、实现ObjectMap...

java BigDecimal(String val)确保小数点后有效位数 ✨ 每日积累

float输出,前7位有效数字是真实值,第8位是估算值,可能和原始一致,可能是四舍五入上来的。double值,前15位有效数字是真实值,第16位是估算值,可能和原始一致,可能是四舍五入上来的。当小数点后的有效位数超过float和doulbe的有效位置之后...

java.math.BigDecimal常用方法

+构造函数 BigDecimal(BigInteger val) 将BigInteger转化为BigDecimal。 BigDecimal(BigInteger unscaledVal, int scale) 将B...

Java 使用BigDecimal进行高精度加减乘除

有时候我们计算金钱或者其他一些计算的时候需要高精度的计算加减乘除,可以使用BigDecimal 加: BigDecimal num1 = new BigDecimal("100.569"); BigDecimal num2 = new Big...

BigDecimal转为int类型

BigDecimal转为int类型

直接调用BigDecimal的intValue()方法 示例: BigDecimal a = new BigDecimal(“1.1”); int b = a.intValue(); BigDecimal运算方法:...

BigDecimal<转载>

前言 我们都知道浮点型变量在进行计算的时候会出现丢失精度的问题。如下一段代码: System.out.println(0.05 + 0.01); System.out.println(1.0 - 0.42); System.out.printl...

BigDecimal去除小数位

String cellValue = ""; double numericCellValue = cell.getNumericCellValue(); BigDecimal bd2...

BigDecimal常被忽略的问题

BigDecimal常被忽略的问题

  一:相除精度丢失的问题   BigDecimal的api除法相对加减乘要实现的复杂多了,只介绍常用的我遇到的问题:   问题:两数相除,如果9/3=3整除没问题,但是10/3=0.33333333......除不尽,这里不能让电脑一直除不尽,所以BigD...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。