详解BigDecimal及其加减乘除运算

详解BigDecimal及其加减乘除运算目录一 BigDecimal 概述二 构造函数详解 1 BigDecimal intval 2 BigDecimal intval MathContextm 3 BigDecimal longval 4 BigDecimal longval MathContextm 5 BigDecimal BigIntegerva 6 BigDecima

 

目录

 

一、BigDecimal概述

二、构造函数详解

1、BigDecimal(int val)

2、BigDecimal(int val, MathContext mc)

     MathContext

3、BigDecimal(long val)

4、BigDecimal(long val, MathContext mc)

5、BigDecimal(BigInteger val)

6、BigDecimal(BigInteger unscaledVal, int scale)

7、BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)

8、BigDecimal(BigInteger val, MathContext mc)

9、BigDecimal(double val)

10、BigDecimal(double val, MathContext mc)

11、BigDecimal(char[] in)

12、BigDecimal(char[] in, int offset, int len)

13、BigDecimal(char[] in, int offset, int len, MathContext mc)

14、BigDecimal(char[] in, MathContext mc)

15、BigDecimal(String val)

16、BigDecimal(String val, MathContext mc)

三、BigDecimal的加、减、乘、除、绝对值

1、加法

2、减法

3、乘法

4、除法

     RoundingMode

5、绝对值

 


一、BigDecimal概述

       浮点数值不适用于无法接受舍入误差的计算当中,比如金融计算。

       例如,System.out.println(2.0-1.1)打印的结果为0.99999,而不是人们想象当中的0.9,这是为什么呢?因为System.out.println()中的数字默认是double类型的,而浮点数值采用二进制系统表示,而在二进制系统中无法精确地表示小数0.1,因此产生了这种舍入误差。

       就像在十进制当中,无法精确地表示分数1/3一样。

       既然浮点数都不能精确的表示出来,那么通过浮点数进行的加减乘除运算自然都不是精确的值。

       如果在数值计算中需要精确的结果,不允许有这种舍入误差,那么就需要使用BigDecima类。

       BigDecima是java.math包中的一个类,这个类可以处理任意长度数字序列的数值,实现了任意精度的浮点数运算。类似BigDecima,还有一个Biglnteger,实现了任意精度的整数运算。

 

       BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。

二、构造函数详解

1、BigDecimal(int val)

       将 int转换成 BigDecimal对象。例如:

       BigDecimal a = new BigDecimal(8);

       这是通过构造函数的方式,将一个整型值转换成BigDecimal 对象,还可以通过静态的valueOf方法将普通的数值转换成BigDecimal。例如:

       BigDecimal b = BigDecimal.valueOf(100);将long型数值转换成(小数位数为零的)BigDecimal。

       BigDecimal c = BigDecimal.valueOf(3.14);将double型数值转换成BigDecimal。

2、BigDecimal(int val, MathContext mc)

       将 int转换成 BigDecimal ,根据上下文设置进行舍入。

       这里需要先讲述一下MathContext

     MathContext

       MathContext是一个不可变对象,用于封装上下文设置,这些设置描述数字运算符的某些规则。它有三个构造函数:

(1)MathContext(int setPrecision)

       构造具有指定精度的MathContext对象,默认的是HALF_UP舍入模式(关于舍入模式,本文后面会进行详细讲解)。

(2)MathContext(int setPrecision, RoundingMode setRoundingMode)

       使用指定的精度和舍入模式构造新的MathContext对象。

(3)MathContext(String val)

       使用字符串构造一个MathContext对象。

       使用示例如下,

MathContext mathContext = new MathContext(4); BigDecimal d = new BigDecimal(12345, mathContext); System.out.println(d);

       打印的结果为:1.235E+4

       分析上述代码。第一行代码创建了一个MathContext 对象,指定的精度为4,也就是4位有效数字。第二行代码利用整型的“12345”和mathContext创建了一个BigDecimal对象,将12345保留4位有效数字转换成BigDecimal。12345保留四位有效数字的结果也就是1.235E+4(1.235乘于10的四次方)。

3、BigDecimal(long val)

       将 long转换成 BigDecimal 。

4、BigDecimal(long val, MathContext mc)

       将 long转换为 BigDecimal ,根据上下文设置进行舍入。

5、BigDecimal(BigInteger val)

       将 BigInteger转换成 BigDecimal 。

6、BigDecimal(BigInteger unscaledVal, int scale)

       将BigInteger的 BigInteger值和 int等级转换为 BigDecimal 。

7、BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)

       将 BigInteger未缩放值,根据scale和mc ,转换为 BigDecimal 。

8、BigDecimal(BigInteger val, MathContext mc)

       根据上下文设置将 BigInteger转换为 BigDecimal,根据上下文设置进行舍入。

9、BigDecimal(double val)

       将 double转换为 BigDecimal ,这是 double的二进制浮点值的精确十进制表示。

10、BigDecimal(double val, MathContext mc)

       将 double转换为 BigDecimal ,根据上下文设置进行舍入。

11、BigDecimal(char[] in)

       将字符数组转换成 BigDecimal 。

12、BigDecimal(char[] in, int offset, int len)

       将字符数组转换成 BigDecimal,同时允许一个子阵列被指定。

13、BigDecimal(char[] in, int offset, int len, MathContext mc)

       将字符数组转换成 BigDecimal,同时允许指定一个子阵列和用根据上下文设置进行舍入。

14、BigDecimal(char[] in, MathContext mc)

      将字符数组转换成 BigDecimal ,根据上下文设置进行舍入。

15、BigDecimal(String val)

       常用!!!将字符串表示的数字转换为 BigDecimal 。

16、BigDecimal(String val, MathContext mc)

       常用!!!将字符串表示的数字转换为 BigDecimal ,根据上下文设置进行舍入。

       可以看到,BigDecimal的构造函数很多,根据自己的需要,大家选择合适的构造函数创建对应的BigDecimal对象就行了。但是有一点需要注意,就是以数值型参数创建BigDecimal对象的时候,会产生精度问题。

      例如,

System.out.println(new BigDecimal(0.1)); System.out.println(new BigDecimal("0.1"));

       打印结果为:

 

       可以看到,通过double类型的0.1创建BigDecimal对象的时候,实际打印的值并不是精确的0.1,通过String类型创建的BigDecimal对象,实际打印的值是0.1。这是为什么呢?

       因为参数类型为double的构造方法的结果有一定的不可预知性。不熟悉BigDecimal的人可能会认为在Java中通过newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1,但是它实际上等于0.00000015625。因为0.1无法用二进制精确地表示出来,本来开头亦对此进行了解释。这样,传入到构造方法的值并不是我们看到的0.1,实际上传的是0.00000015625,因此产生了上述的打印结果。

       String 构造方法是完全可预知的:通过 newBigDecimal(“0.1”) 将创建一个 BigDecimal对象,它正好等于预期的 0.1。因此, 通常建议优先使用String构造方法。

三、BigDecimal的加、减、乘、除、绝对值

1、加法

       加法对应的方法有两个:

(1)public BigDecimal add(BigDecimal augend);

       方法返回的是一个BigDecimal对象,值为当前对象的值加上被加数对象augend的值(this+augend)。保留的小数位数是max(this.scale(), augend.scale()).

(2) public BigDecimal add(BigDecimal augend,MathContext mc);

       方法返回的是一个BigDecimal对象,值为当前对象的值加上被加数对象augend的值(this+augend),并根据上下文设置进行舍入。(关于上下文MathContext,前文已解释过)

       加法示例如下,

 @Test public void testAdd() { //用double类型初始化BigDecimal对象 BigDecimal numA = new BigDecimal(0.05); BigDecimal numB = new BigDecimal(0.06); System.out.println("numA + numB = " + numA.add(numB)); //用double类型和int类型初始化BigDecimal对象。(作加法运算时得到的只是一个近似值) BigDecimal numC = new BigDecimal(3.05); BigDecimal numD = new BigDecimal(100); System.out.println("numC + numD = " + numC.add(numD)); //用字符串类型初始化BigDecimal对象。(作加法运算时得到的是精确值) BigDecimal strA = new BigDecimal("3.05"); BigDecimal strB = new BigDecimal("100"); System.out.println("strA + strB = " + strA.add(strB)); }

      打印的结果如下:

       可以看到,使用double类型初始化BigDecimal 对象,进行加法运算时就出现了精度问题。正如前文所说,并不是所有的浮点数都能够在二进制系统中被精确的表示,自然而然的在进行加减乘除运算时就会出错。

2、减法

       方法返回的是一个BigDecimal对象,值为当前对象的值减去被减数对象subtrahend的值(this-subtrahend)。保留的小数位数是max(this.scale(), subtrahend.scale()).。   

(2)public BigDecimal subtract(BigDecimal subtrahend,MathContext mc);

       方法返回的是一个BigDecimal对象,值为当前对象的值减去被减数对象subtrahend的值(this-subtrahend),并根据上下文设置进行舍入。

       减法示例如下,

 @Test public void testSubtract() { //用double类型初始化BigDecimal对象 BigDecimal numA = new BigDecimal(0.05); BigDecimal numB = new BigDecimal(0.06); System.out.println("numA + numB = " + numA.subtract(numB)); //用double类型和int类型初始化BigDecimal对象。(作减法运算时得到的只是一个近似值) BigDecimal numC = new BigDecimal(100); BigDecimal numD = new BigDecimal(0.05); System.out.println("numC + numD = " + numC.subtract(numD)); //用字符串类型初始化BigDecimal对象。(作减法运算时得到的是精确值) BigDecimal strA = new BigDecimal("100"); BigDecimal strB = new BigDecimal("0.05"); System.out.println("strA + strB = " + strA.subtract(strB)); }

       打印结果如下:

3、乘法

       对应的方法有:

(1)public BigDecimal multiply(BigDecimal multiplicand);

       方法返回的是一个BigDecimal对象,值为当前对象的值乘于被乘数对象multiplicand的值(this*multiplicand)。保留的小数位数是(this.scale() + multiplicand.scale()).。   

(2)public BigDecimal multiply(BigDecimal multiplicand,MathContext mc);

      方法返回的是一个BigDecimal对象,值为当前对象的值乘于被乘数对象subtrahend的值(this*multiplicand),并根据上下文设置进行舍入。

      乘法示例如下,

 @Test public void testMultiply() { //用double类型初始化BigDecimal对象 BigDecimal numA = new BigDecimal(0.05); BigDecimal numB = new BigDecimal(0.06); System.out.println("numA + numB = " + numA.multiply(numB)); //用double类型和int类型初始化BigDecimal对象。(作乘法运算时得到的只是一个近似值) BigDecimal numC = new BigDecimal(100); BigDecimal numD = new BigDecimal(0.05); System.out.println("numC + numD = " + numC.multiply(numD)); //用字符串类型初始化BigDecimal对象。(作乘法运算时得到的是精确值) BigDecimal strA = new BigDecimal("100"); BigDecimal strB = new BigDecimal("0.05"); System.out.println("strA + strB = " + strA.multiply(strB)); }

       打印结果如下,

numA + numB = 0.00000000875 numC + numD = 5.0000000000000000 strA + strB = 5.00

 

4、除法

       对应的方法主要有:

(1) public BigDecimal divide(BigDecimal divisor);

       返回一个BigDecimal,其值为(this/divisor),首选小数位数为(this.scale()-divisor.scale());如果无法表示精确的商(因为它具有非终止的十进制扩展),则会引发算术异常。

(2) public BigDecimal divide(BigDecimal divisor,MathContext mc);

       返回值为(this/divisor)的BigDecimal,并根据上下文设置进行舍入。

 (3) public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode);

       返回一个BigDecimal,其值为(this/divisor),其小数位数与指定的相同。如果必须执行舍入才能生成具有指定比例的结果,则应该用指定的舍入模式。

(4) public BigDecimal divide(BigDecimal divisor,int scale,RoundingMode roundingMode);

       返回一个BigDecimal,其值为(this/divisor),其小数位数与指定的相同(由第二个参数scale指定)。如果必须执行舍入才能生成具有指定比例的结果,则应该用指定的舍入模式(由第三个参数roundingMode指定)。

       (3)(4)两个方法其实是一样的,区别只在于第三个参数的指定方式。第一个方法是int roundingMode,即传入的是一个整型数字,而第二个方法是RoundingMode roundingMode,即传入的是一个RoundingMode对象。

       这里需要对RoundingMode作一下介绍。

     RoundingMode

       RoundingMode是一个枚举类,内部有8个枚举常量,分别是:

       UP:远离0的舍入模式,在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。放到一维坐标轴上就很容易理解,就是以0为分隔点,0右侧部分一直向右舍入,0左侧部分一直向左侧舍入。例如0.333保留两位小数,采用UP舍入模式的结果为0.34,-0.333保留两位小数,采用UP舍入模式的结果为-0.34。

详解BigDecimal及其加减乘除运算

       DOWN:和UP相反,是接近零的舍入模式。理解了UP舍入模式,就很容易理解DOWN舍入模式。例如0.333保留两位小数,采用DOWN舍入模式的结果为0.33,-0.333保留两位小数,采用DOWN舍入模式的结果为-0.33。可以发现,在采用DOWN模式进行舍入的时候,直接把需要舍弃的位数丢掉就行了。

详解BigDecimal及其加减乘除运算

       CEILING:CEILING英文是天花板的意思,可以理解为向”大“舍入。如果 BigDecimal 为正,则舍入行为与 UP 相同,如果为负,则舍入行为与 DOWN 相同。例如0.333保留两位小数,采用CEILING舍入模式的结果为0.34(0.34 >0.333),-0.333保留两位小数,采用CEILING舍入模式的结果为-0.33(-0.33>0.333 )。

详解BigDecimal及其加减乘除运算

       FLOOR:与CEILING相反,FLOOR有地板的意思,可以理解为向”小“舍入。如果 BigDecimal 为正,则舍入行为与 DOWN 相同,如果为负,则舍入行为与 UP 相同。例如0.333保留两位小数,采用FLOOR舍入模式的结果为0.33,-0.333保留两位小数,采用FLOOR舍入模式的结果为-0.34。

详解BigDecimal及其加减乘除运算

       HALF_UP:向”最接近的“数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 >= 0.5,则舍入行为与 UP 相同,否则舍入行为与 DOWN 相同。其实就是四舍五入。

       HALF_DOWN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 > 0.5,则舍入行为与UP 相同,否则舍入行为与 DOWN 相同。与四舍五入的思路是一样的,只不过这里是”五舍六入“。如果扣字面意思的话,也很好理解,HALF_UP,half是一半的意思,也就是5,UP是向上的意思,就可以理解为5向上入,即四舍五入。同理,HALF_DOWN,5向下舍,即五舍六入。

       HALF_EVEN:向“最接近的”数字舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 UP 相同,如果为偶数,则舍入行为与 DOWN 相同。如0.135,保留两位小数,舍弃5,因为3是奇数,所以与UP相同,结果为0.14;0.125,保留两位小数,舍弃5,因为2是偶数,所以与DOWN相同,结果为0.12.

       UNNECESSARY:以断言请求的操作具有精确的结果,因此不需要舍入。如果有舍入,会报java.lang.ArithmeticException异常。

       关于这几个舍入模式的结果,亦可参照下面的表进行快速学习。

保留整数,不同舍入模式下的计算结果
原数 UP DOWN CEILING FLOOR HALF_UP HALF_DOWN HALF_EVEN UNNECESSARY
5.5 6 5 6 5 6 5 6 throw ArithmeticException
2.5 3 2 3 2 3 2 2 throw ArithmeticException
1.6 2 1 2 1 2 2 2 throw ArithmeticException
1.1 2 1 2 1 1 1 1 throw ArithmeticException
1.0 1 1 1 1 1 1 1 1
-1.0 -1 -1 -1 -1 -1 -1 -1 -1
-1.1 -2 -1 -1 -2 -1 -1 -1 throw ArithmeticException
-1.6 -2 -1 -1 -2 -2 -2 -2 throw ArithmeticException
-2.5 -3 -2 -2 -3 -3 -2 -2 throw ArithmeticException
-5.5 -6 -5 -5 -6 -6 -5 -6 throw ArithmeticException
                 

       代码示例如下,

@Test public void testDivide() { BigDecimal numA = new BigDecimal("1"); BigDecimal numB = new BigDecimal("-1"); BigDecimal numC = new BigDecimal("3"); // 保留两位小数,舍入模式为UP System.out.println("1/3保留两位小数(UP) = " + numA.divide(numC, 2, RoundingMode.UP)); System.out.println("-1/3保留两位小数(UP) = " + numB.divide(numC, 2, RoundingMode.UP)); // 保留两位小数,舍入模式为DOWN System.out.println("1/3保留两位小数(DOWN) = " + numA.divide(numC, 2, RoundingMode.DOWN)); System.out.println("-1/3保留两位小数(DOWN) = " + numB.divide(numC, 2, RoundingMode.DOWN)); // 保留两位小数,舍入模式为CEILING System.out.println("1/3保留两位小数(CEILING) = " + numA.divide(numC, 2, RoundingMode.CEILING)); System.out.println("-1/3保留两位小数(CEILING) = " + numB.divide(numC, 2, RoundingMode.CEILING)); // 保留两位小数,舍入模式为FLOOR System.out.println("1/3保留两位小数(FLOOR) = " + numA.divide(numC, 2, RoundingMode.FLOOR)); System.out.println("-1/3保留两位小数(FLOOR) = " + numB.divide(numC, 2, RoundingMode.FLOOR)); BigDecimal numD = new BigDecimal("1"); BigDecimal numE = new BigDecimal("-1"); BigDecimal numF = new BigDecimal("8"); // 保留两位小数,舍入模式为HALF_UP System.out.println("1/8(=0.125)保留两位小数(HALF_UP) = " + numD.divide(numF, 2, RoundingMode.HALF_UP)); System.out.println("-1/8(=0.125)保留两位小数(HALF_UP) = " + numE.divide(numF, 2, RoundingMode.HALF_UP)); // 保留两位小数,舍入模式为HALF_DOWN System.out.println("1/8(=0.125)保留两位小数(HALF_DOWN) = " + numD.divide(numF, 2, RoundingMode.HALF_DOWN)); System.out.println("-1/8(=0.125)保留两位小数(HALF_DOWN) = " + numE.divide(numF, 2, RoundingMode.HALF_DOWN)); // 保留两位小数,舍入模式为HALF_EVEN System.out.println("0.54/4(=0.135)保留两位小数(HALF_EVEN) = " + new BigDecimal("0.54").divide(new BigDecimal("4"), 2, RoundingMode.HALF_EVEN)); System.out.println("1/8(=0.125)保留两位小数(HALF_EVEN) = " + numE.divide(numF, 2, RoundingMode.HALF_EVEN)); //UNNECESSARY,会报异常 System.out.println("1/8(=0.125) = " + numE.divide(numF, RoundingMode.UNNECESSARY)); }

打印结果:

java.lang.ArithmeticException: Rounding necessary

5、绝对值

 public BigDecimal abs();

       返回一个BigDecimal,其值为该BigDecimal的绝对值,其小数位数为this.scale()。

 public BigDecimal abs(MathContext mc);

      返回一个BigDecimal,其值是此BigDecimal的绝对值,并根据上下文设置进行舍入。

      代码示例,

 @Test public void testAbs() { BigDecimal a = new BigDecimal("1.234"); BigDecimal b = new BigDecimal("-1.234"); System.out.println("1.234的绝对值:" + a.abs()); System.out.println("-1.234的绝对值:" + b.abs()); System.out.println("-1.234的绝对值,保留两位有效数字:" + b.abs(new MathContext(2))); }

       打印结果为:

 

详解BigDecimal及其加减乘除运算

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/227020.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午10:07
下一篇 2026年3月16日 下午10:08


相关推荐

  • 最长公共子串 动态规划_最长公共子上升序列

    最长公共子串 动态规划_最长公共子上升序列原题链接题目描述给定两个字符串str1和str2,输出连个字符串的最长公共子序列。如过最长公共子序列为空,则输出-1。输入描述:输出包括两行,第一行代表字符串str1,第二行代表str2。( 1<= length(str1),length(str2)<= 5000)输出描述:输出一行,代表他们最长公共子序列。如果公共子序列的长度为空,则输出-1。示例1输入1A2C3D4B56B1D23CA45B6A输出123456说明”123456″和“12C4B6”都是最长公共

    2022年8月8日
    4
  • 空间流介绍[通俗易懂]

    空间流介绍[通俗易懂]stream是802.11n中的空间流的意思,11n协议中最高支持4空间流。11n协议物理层最核心的技术就是MIMO技术,一般AP设备MIMO都后注1×1,2×2,2×3,3×3等,这两个数字前面一个数字式11nAP的发射天线数量,后面一个数字是11nAP的接受天线数量。11n中所谓的空间流实际就是MIMO空间复用支持的多根天线独立地并行发送由单独编码的信号组成的不同的数据流。无线复用的空间流的数量取决于发射天线的数量。你可以这样简单理解,由于11nAP有多个发射天线,形成多个发射物理信道,与以前的WLA

    2022年7月21日
    41
  • jQuery页面滚动右侧浮动导航切换

    体验效果:http://hovertree.com/texiao/jquery/49/效果图:代码如下:转自:http://hovertree.com/h/bjaf/2slij8q4.htm参

    2021年12月22日
    49
  • python可以自动回收垃圾吗_python 数据清洗

    python可以自动回收垃圾吗_python 数据清洗前言现在的高级语言如java,c#等,都采用了垃圾回收机制,而不再像c,c++里,需要用户自己管理内存。自己管理内存及其自由,可以任意申请内存,但这如同一把双刃剑,可能会造成内存泄漏,空指针等bug

    2022年7月28日
    10
  • pycharm怎么编译代码_python编程

    pycharm怎么编译代码_python编程python可以说是新的编程语言,虽说是新编程,但一出来,就受到很长程序员的关注,而且刚出现和java进行对比,很多人就拿python和java进行比较,想python到底好不好,他和java有什么区别,要想知道他们的区别,还是要了解python比较好,要知道python知识,今天我们就来看看python里的pycharm编写代码的方式教学。1、新建项目location:为创建项目的地址(或者叫文…

    2022年8月28日
    7
  • db2事务隔离级别设置_db2存储过程

    db2事务隔离级别设置_db2存储过程Jdbc事务隔离级别 Jdbc隔离级别 数据库隔离级别 数据访问情况 TRANSACTION_READ_UNCOMMITTED(未提交读)UncommittedRead ur 脏读,在没有提交数据的时候能够读到已经更新的数据 TRANSACTION_READ_C…

    2022年10月14日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号