Java BigDecimal类及其示例

时间:2020-01-09 10:34:51  来源:igfitidea点击:

如果我们在需要精确值的Java应用程序中进行某些计算,例如在财务操作中,则不应使用float或者double基本类型。如果要存储非常大的数字,则采用相同的方法,例如,如果要计算阶乘,则长或者双精度可能会再次下降。在这种情况下,我们应该使用Java BigDecimal类代替,该类提供用于算术,缩放操作,舍入,比较,哈希和格式转换的操作。由于它是一个类,因此它的对象可以存储仅受计算机内存限制的很大的值,因此我们可以在BigDecimal类对象中存储大量的数字。

Java中的BigDecimal类还向用户提供了对舍入行为的完全控制,这是进行财务计算时的另一个常见要求。

让我们举个例子来看一下,如何使用float或者double可能会给我们带来错误的价值

double d1 = 78.95;
double d2 = 67.55;
System.out.println("d1 - d2= " + (d1-d2));

我们会期望输出为11.40,但是输出isd1 – d2 = 11.400000000000006

因此,我们可以看到一些近似值,而不是获得精确值。如果使用BigDecimals进行相同的计算,则将获得正确的值。

BigDecimal b1 = new BigDecimal("78.95");
BigDecimal b2 = new BigDecimal("67.55");
System.out.println("b1 - b2= " + b1.subtract(b2)); // b1 - b2= 11.40

Java BigDecimal构造函数

在Java BigDecimal类中,有许多构造函数,可以使用char [],int,double,long,String,BigDecimal初始化BigDecimal对象。以下是一些传递特定类型的构造函数

  • BigDecimal(char [] in)

  • BigDecimal(int val)

  • BigDecimal(字符串val)

有些构造函数会将MathContext实例与值一起作为第二个参数传递。以下是一些构造函数

  • BigDecimal(char [] in,MathContext mc)

  • BigDecimal(int val,MathContext mc)

  • BigDecimal(long val,MathContext mc)

MathContext实例封装了上下文设置,这些上下文描述描述了数值运算符的某些规则,例如精度设置,舍入模式

  • DECIMAL32 –一个MathContext对象,其精度设置为7位(与IEEE 754R Decimal32格式匹配),并且舍入模式为HALF_EVEN(默认为IEEE 754R)。

  • DECIMAL64 –一个MathContext对象,其精度设置为16位(与IEEE 754R Decimal64格式匹配)并且舍入模式为HALF_EVEN(默认为IEEE 754R)。

  • DECIMAL128 –一个MathContext对象,其精度设置为34位(与IEEE 754R Decimal128格式匹配)并且舍入模式为HALF_EVEN(默认为IEEE 754R)。

  • UNLIMITED –一个MathContext对象,其设置具有无限精度算术所需的值。

创建通过int和MathContext的BigDecimal实例的示例。

BigDecimal b1 = new BigDecimal(6, MathContext.DECIMAL64);

还有一些构造函数可以将scale作为参数传递,并同时传递scale和MathContext实例。

  • BigDecimal(BigInteger unscaledVal,int scale)

  • BigDecimal(BigInteger unscaledVal,int scale,MathContext mc)

这是一个传递BigInteger实例和小数位数以创建BigDecimal实例的示例。

BigInteger bi = new BigInteger("4567898");
int scale = 2;
BigDecimal bd = new BigDecimal(bi, scale);
System.out.println(bd); // 45678.98

BigDecimal中的舍入模式

Java BigDecimal类的一项便利功能是传递舍入模式,该模式指定数字运算的舍入行为。 RoundingMode是包java.math中提供的Enum,它提供以下Enum常量。

  • CEILING–取整模式可以向正无穷大取整。

  • DOWN–舍入模式将舍入为零。

  • FLOOR –取整模式,取整为负无穷大。

  • HALF_DOWN –舍入模式向"最近的邻居"舍入,除非两个邻居都等距,在这种情况下舍入。

  • HALF_EVEN –舍入模式向"最近的邻居"舍入,除非两个邻居都等距,在这种情况下,向偶数邻居舍入。

  • HALF_UP –舍入模式向"最近的邻居"舍入,除非两个邻居等距。

  • UNNECESSARY-舍入模式可以断言所请求的操作具有准确的结果,因此不需要舍入。

  • UP–舍入模式从零舍入。

这是一个汇总表,显示了所有舍入模式下这些舍入运算的结果。

输入数字UPDOWNCEILINGFLOORHALF_UPHALF_DOWNHALF_EVENUNNECESSARY
5.565656抛出算术异常
2.532322抛出算术异常
1.62122抛出算术异常
1.121211抛出算术异常
1.011111111
-1.0-1-1-1-1-1-1-1-1
-1.1-2-1-1-2-1-1-1抛出算术异常
-1.6-2-1-1-2-2-2抛出算术异常
-2.5-3-2-2-3-3-2-2抛出算术异常
-5.5-6-5-5-6-6-5-6抛出算术异常

Java BigDecimal中的缩放方法

提供小数位数(小数点后的位数)和舍入模式的方法可能是BigDecimal类中最常用的方法。

  • setScale(int newScale)–返回一个BigDecimal,其小数位数是指定值,并且其数值在数值上等于该BigDecimal的数值。

  • setScale(int newScale,RoundingMode roundingMode)–设置缩放和舍入模式的方法。

BigDecimal bd = new BigDecimal("4567.876");
System.out.println("BigDecimal- " + bd);
System.out.println("BigDecimal(RoundingMode.DOWN)- " + bd.setScale(2, RoundingMode.DOWN));
System.out.println("BigDecimal(RoundingMode.CEILING)- " + bd.setScale(2, RoundingMode.CEILING));
System.out.println("BigDecimal(RoundingMode.FLOOR)- " + bd.setScale(2, RoundingMode.FLOOR));
System.out.println("BigDecimal(RoundingMode.HALF_DOWN)- " + bd.setScale(2, RoundingMode.HALF_DOWN));
System.out.println("BigDecimal(RoundingMode.HALF_EVEN)- " + bd.setScale(2, RoundingMode.HALF_EVEN));

输出:

BigDecimal- 4567.876
BigDecimal(RoundingMode.DOWN)- 4567.87
BigDecimal(RoundingMode.CEILING)- 4567.88
BigDecimal(RoundingMode.FLOOR)- 4567.87
BigDecimal(RoundingMode.HALF_DOWN)- 4567.88
BigDecimal(RoundingMode.HALF_EVEN)- 4567.88

BigDecimal方法示例

让我们看一下Java BigDecimal类中用于执行算术运算的其他一些方法的示例。

  1. Java对象中不允许使用算术运算符(+,-,*,/),因此这些运算符也不能与BigDecimal实例一起使用。 BigDecimal类中有加,减,乘和除的方法来执行这些算术运算。
  • add(BigDecimal bd2)–返回其值为(this + bd2)的BigDecimal。

  • split(BigDecimal divisor)–返回其值为(this / divisor)的BigDecimal。

  • 除法(BigDecimal除数,整数刻度,RoundingMode roundingMode)-返回一个BigDecimal,其值为(this / divisor),其刻度已指定。

  • 乘法(BigDecimal bd2)-返回一个BigDecimal,其值为(this×bd2)

  • 减法(BigDecimal bd2)–返回其值为(this – bd2)的BigDecimal。

public class BDDemo {
  public static void main(String[] args) throws IOException {
    BigDecimal bd1 = new BigDecimal("4567.876");
    BigDecimal bd2 = new BigDecimal(4000.676);
    
    System.out.println("BigDecimal addition- " + bd1.add(bd2).setScale(2, RoundingMode.HALF_EVEN));
    System.out.println("BigDecimal subtraction- " + bd1.subtract(bd2).setScale(2, RoundingMode.HALF_EVEN));
    System.out.println("BigDecimal multiplication)- " + bd1.multiply(bd2).setScale(2, RoundingMode.HALF_EVEN));
    System.out.println("BigDecimal division- " + bd1.divide(bd2, 2, RoundingMode.HALF_EVEN));
  }
}

输出:

BigDecimal addition- 8568.55
BigDecimal subtraction- 567.20
BigDecimal multiplication)- 18274591.88
BigDecimal division- 1.14
  1. BigDecimal中的max和min方法
  • max(BigDecimal val)–返回此BigDecimal和val的最大值。

  • min(BigDecimal val)–返回此BigDecimal和val的最小值。

BigDecimal bd1 = new BigDecimal("4567.876");
BigDecimal bd2 = new BigDecimal("4000.676");

System.out.println("Max BigDecimal- " + bd1.max(bd2));
System.out.println("Min BigDecimal- " + bd1.min(bd2));

输出:

Max BigDecimal- 4567.876
Min BigDecimal- 4000.676
  1. BigDecimal中的Pow方法
  • pow(int n)-返回BigDecimal,其值为(this n)。
BigDecimal bd = new BigDecimal("45");
System.out.println("45^4- " + bd.pow(4)); // 4100625

比较两个BigDecimals

尽管为了检查对象是否相等,我们将使用equals方法,但是此方法不适用于BigDecimal数字,因为此方法仅在两个BigDecimal对象的值和小数均相等时才认为它们相等,因此,如果equals方法为5.0,则5.0不等于5.00用过的。

为了比较BigDecimals,使用compareTo()方法。

  • compareTo(BigDecimal val)–将此BigDecimal与指定的BigDecimal进行比较。此方法将值相等但规模不同(例如2.0和2.00)的两个BigDecimal对象视为相等。如果小于val,则返回-1. 如果两者相等,则为0。如果大于val,则为1.
BigDecimal bd1 = new BigDecimal("5.00");
BigDecimal bd2 = new BigDecimal("5.0");
System.out.println("bd1 equals bd2 - " + bd1.equals(bd2));
System.out.println("bd1 compare to bd2 - " + bd1.compareTo(bd2));

输出:

bd1 equals bd2 - false
bd1 compare to bd2 - 0