BigDecimal and BigInteger in Java – Java中的BigDecimal和BigInteger

最后修改: 2017年 7月 1日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we will demonstrate BigDecimal and the BigInteger classes.

在本教程中,我们将演示BigDecimal BigInteger 类。

We’ll describe the two data types, their characteristics, and their usage scenarios. We’ll also briefly cover the various operations using the two classes.

我们将描述这两种数据类型,它们的特点,以及它们的使用场景。我们还将简要地介绍使用这两个类的各种操作。

2. BigDecimal

2、BigDecimal

BigDecimal represents an immutable arbitrary-precision signed decimal number. It consists of two parts:

BigDecimal表示一个不可改变的任意精度的有符号十进制数。它由两部分组成。

  • Unscaled value – an arbitrary precision integer
  • Scale – a 32-bit integer representing the number of digits to the right of the decimal point

For example, the BigDecimal 3.14 has the unscaled value of 314 and the scale of 2.

例如,BigDecimal 3.14的未标度值为314,标度为2。

We use BigDecimal for high-precision arithmetic. We also use it for calculations requiring control over scale and rounding off behavior.  One such example is calculations involving financial transactions.

我们使用BigDecimal进行高精度运算。我们还将其用于需要控制比例和舍入行为的计算。 其中一个例子是涉及金融交易的计算。

We can create a BigDecimal object from String, character array, int, long, and BigInteger:

我们可以从String、字符数组、intlongBigInteger创建一个BigDecimal对象。

@Test
public void whenBigDecimalCreated_thenValueMatches() {
    BigDecimal bdFromString = new BigDecimal("0.1");
    BigDecimal bdFromCharArray = new BigDecimal(new char[] {'3','.','1','6','1','5'});
    BigDecimal bdlFromInt = new BigDecimal(42);
    BigDecimal bdFromLong = new BigDecimal(123412345678901L);
    BigInteger bigInteger = BigInteger.probablePrime(100, new Random());
    BigDecimal bdFromBigInteger = new BigDecimal(bigInteger);
        
    assertEquals("0.1",bdFromString.toString());
    assertEquals("3.1615",bdFromCharArray.toString());
    assertEquals("42",bdlFromInt.toString());
    assertEquals("123412345678901",bdFromLong.toString());
    assertEquals(bigInteger.toString(),bdFromBigInteger.toString());
}

We can also create BigDecimal from double:

我们也可以从double创建BigDecimal

@Test
public void whenBigDecimalCreatedFromDouble_thenValueMayNotMatch() {
    BigDecimal bdFromDouble = new BigDecimal(0.1d);
    assertNotEquals("0.1", bdFromDouble.toString());
}

However,  the result, in this case, is different from expected (that is 0.1). This is because:

然而,在这种情况下,其结果与预期不同(即0.1)。这是因为。

  • the double constructor does an exact translation
  • 0.1 does not have an exact representation in double

Therefore, we should use the String constructor instead of the double constructor.

因此,我们应该使用String构造函数而不是double构造函数

In addition, we can convert double and long to BigDecimal using the valueOf static method:

此外,我们可以使用valueOf静态方法将doublelong转换成BigDecimal

@Test
public void whenBigDecimalCreatedUsingValueOf_thenValueMatches() {
    BigDecimal bdFromLong1 = BigDecimal.valueOf(123412345678901L);
    BigDecimal bdFromLong2 = BigDecimal.valueOf(123412345678901L, 2);
    BigDecimal bdFromDouble = BigDecimal.valueOf(0.1d);

    assertEquals("123412345678901", bdFromLong1.toString());
    assertEquals("1234123456789.01", bdFromLong2.toString());
    assertEquals("0.1", bdFromDouble.toString());
}

This method converts double to its String representation before converting to BigDecimal. In addition, it may reuse object instances.

该方法在转换为BigDecimal之前,将double转换为其String表示。此外,它可能会重复使用对象实例。

Hence, we should use the valueOf method in preference to the constructors.

因此,我们应该优先使用valueOf方法,而不是构造函数

3. Operations on BigDecimal

3.对BigDecimal的操作

Just like the other Number classes (Integer, Long, Double etc.), BigDecimal provides operations for arithmetic and comparison operations. It also provides operations for scale manipulation, rounding and format conversion.

就像其他Number类(Integer, Long, Double等),BigDecimal提供了算术和比较操作。它还提供了刻度操作、四舍五入和格式转换的操作。

It does not overload the the arithmetic (+, -, /, *) or logical (>. < etc) operators. Instead, we use the corresponding methods – add, subtract, multiply, divide and compareTo.

它没有重载算术(+, -, /, *)或逻辑(>. <等)运算符。相反,我们使用相应的方法 – add, subtract, multiply, dividecompareTo.

BigDecimal has methods to extract various attributes, such as precision, scale, and sign:

BigDecimal有一些方法可以提取各种属性,如精度、比例和符号

@Test
public void whenGettingAttributes_thenExpectedResult() {
    BigDecimal bd = new BigDecimal("-12345.6789");
        
    assertEquals(9, bd.precision());
    assertEquals(4, bd.scale());
    assertEquals(-1, bd.signum());
}

We compare the value of two BigDecimals using the compareTo method:

我们使用compareTo方法比较两个BigDecimals的值

@Test
public void whenComparingBigDecimals_thenExpectedResult() {
    BigDecimal bd1 = new BigDecimal("1.0");
    BigDecimal bd2 = new BigDecimal("1.00");
    BigDecimal bd3 = new BigDecimal("2.0");

    assertTrue(bd1.compareTo(bd3) < 0);
    assertTrue(bd3.compareTo(bd1) > 0);
    assertTrue(bd1.compareTo(bd2) == 0);
    assertTrue(bd1.compareTo(bd3) <= 0);
    assertTrue(bd1.compareTo(bd2) >= 0);
    assertTrue(bd1.compareTo(bd3) != 0);
}

This method ignores the scale while comparing.

这种方法在比较时忽略了刻度。

On the other hand, the equals method considers two BigDecimal objects as equal only if they are equal in value and scale. Thus, BigDecimals 1.0 and 1.00 are not equal when compared by this method.

另一方面,equals方法认为两个BigDecimal对象只有在数值和比例相等时才是相等的。因此,BigDecimals 1.0和1.00在用这个方法比较时是不相等的。

@Test
public void whenEqualsCalled_thenSizeAndScaleMatched() {
    BigDecimal bd1 = new BigDecimal("1.0");
    BigDecimal bd2 = new BigDecimal("1.00");
        
    assertFalse(bd1.equals(bd2));
}

We perform arithmetic operations by calling the corresponding methods:

我们通过调用相应的方法进行算术运算

@Test
public void whenPerformingArithmetic_thenExpectedResult() {
    BigDecimal bd1 = new BigDecimal("4.0");
    BigDecimal bd2 = new BigDecimal("2.0");

    BigDecimal sum = bd1.add(bd2);
    BigDecimal difference = bd1.subtract(bd2);
    BigDecimal quotient = bd1.divide(bd2);
    BigDecimal product = bd1.multiply(bd2);

    assertTrue(sum.compareTo(new BigDecimal("6.0")) == 0);
    assertTrue(difference.compareTo(new BigDecimal("2.0")) == 0);
    assertTrue(quotient.compareTo(new BigDecimal("2.0")) == 0);
    assertTrue(product.compareTo(new BigDecimal("8.0")) == 0);
}

Since BigDecimal is immutable, these operations do not modify the existing objects. Rather, they return new objects.

由于BigDecimal是不可变的,这些操作不会修改现有的对象。相反,它们会返回新的对象。

4. Rounding and BigDecimal

4.四舍五入和BigDecimal

By rounding a number, we replace it with another having shorter, simpler and more meaningful representation. For example, we round $24.784917 to $24.78 as we do not have fractional cents.

通过四舍五入,我们用另一个更短、更简单、更有意义的数字来代替它。例如,我们将24.784917美元四舍五入为24.78美元,因为我们没有小数点。

The precision and rounding mode to be used varies depending on the calculation. For example, U.S. Federal Tax returns specify to round off to whole dollar amounts using HALF_UP.

要使用的精度和四舍五入模式根据计算的不同而不同。例如,美国联邦税收申报指定使用HALF_UP四舍五入到整美元金额。

There are two classes which control rounding behavior – RoundingMode and MathContext.

有两个控制舍入行为的类–RoundingModeMathContext

The enum RoundingMode provides eight rounding modes:

enum RoundingMode提供了8种四舍五入模式。

  • CEILING – rounds towards positive infinity
  • FLOOR – rounds towards negative infinity
  • UP – rounds away from zero
  • DOWN – rounds towards zero
  • HALF_UP – rounds towards “nearest neighbor” unless both neighbors are equidistant, in which case rounds up
  • HALF_DOWN – rounds towards “nearest neighbor” unless both neighbors are equidistant, in which case rounds down
  • HALF_EVEN – rounds towards the “nearest neighbor” unless both neighbors are equidistant, in which case, rounds towards the even neighbor
  • UNNECESSARY – no rounding is necessary and ArithmeticException is thrown if no exact result is possible

HALF_EVEN rounding mode minimizes the bias due to rounding operations. It is frequently used. It is also known as the banker’s rounding.

HALF_EVEN四舍五入模式将四舍五入操作带来的偏差降到最低。它被经常使用。它也被称为银行家的舍入

MathContext encapsulates both precision and rounding mode.  There are few predefined MathContexts:

MathContext 封装了精度和舍入模式。 有几个预定义的MathContexts。

  • DECIMAL32 – 7 digits precision and a rounding mode of HALF_EVEN
  • DECIMAL64 – 16 digits precision and a rounding mode of HALF_EVEN
  • DECIMAL128 – 34 digits precision and a rounding mode of HALF_EVEN
  • UNLIMITED – unlimited precision arithmetic

Using this class, we can round a BigDecimal number using specified precision and rounding behavior:

使用这个类,我们可以使用指定的精度和舍入行为对BigDecimal数字进行舍入。

@Test
public void whenRoundingDecimal_thenExpectedResult() {
    BigDecimal bd = new BigDecimal("2.5");
    // Round to 1 digit using HALF_EVEN
    BigDecimal rounded = bd
        .round(new MathContext(1, RoundingMode.HALF_EVEN));

    assertEquals("2", rounded.toString());
}

Now, let’s examine the rounding concept using a sample calculation.

现在,让我们用一个计算样本来研究四舍五入的概念。

Let’s write a method to calculate the total amount to be paid for an item given a quantity and unit price. Let’s also apply a discount rate and sales tax rate. We round the final result to cents by using the setScale method:

让我们写一个方法来计算给定数量和单价的物品的总金额。让我们也应用一个折扣率和销售税率。我们通过使用setScale方法将最终结果四舍五入到美分。

public static BigDecimal calculateTotalAmount(BigDecimal quantity,
    BigDecimal unitPrice, BigDecimal discountRate, BigDecimal taxRate) { 
    BigDecimal amount = quantity.multiply(unitPrice);
    BigDecimal discount = amount.multiply(discountRate);
    BigDecimal discountedAmount = amount.subtract(discount);
    BigDecimal tax = discountedAmount.multiply(taxRate);
    BigDecimal total = discountedAmount.add(tax);

    // round to 2 decimal places using HALF_EVEN
    BigDecimal roundedTotal = total.setScale(2, RoundingMode.HALF_EVEN);
        
    return roundedTotal;
}

Now, let’s write a unit test for this method:

现在,让我们为这个方法写一个单元测试。

@Test
public void givenPurchaseTxn_whenCalculatingTotalAmount_thenExpectedResult() {
    BigDecimal quantity = new BigDecimal("4.5");
    BigDecimal unitPrice = new BigDecimal("2.69");
    BigDecimal discountRate = new BigDecimal("0.10");
    BigDecimal taxRate = new BigDecimal("0.0725");

    BigDecimal amountToBePaid = BigDecimalDemo
      .calculateTotalAmount(quantity, unitPrice, discountRate, taxRate);

    assertEquals("11.68", amountToBePaid.toString());
}

5. BigInteger

5.BigInteger

BigInteger represents immutable arbitrary-precision integers. It is similar to the primitive integer types but allows arbitrary large values.

BigInteger表示不可变的任意精度的整数。它与原始整数类型类似,但允许任意大的数值。

It is used when integers involved are larger than the limit of long type. For example, the factorial of 50 is 30414093201713378043612608166064768844377641568960512000000000000. This value is too big for an int or long data type to handle. It can only be stored in a BigInteger variable.

当所涉及的整数大于long类型的极限时,就会使用它。例如,50的阶乘是3041409320171337804361260816606476884437764156896051200000000。这个值对于int或long数据类型来说太大,无法处理。它只能被存储在一个BigInteger变量中。

It is widely used in security and cryptography applications.

它被广泛用于安全和密码学应用。

We can create BigInteger from a byte array or String:

我们可以从一个字节数组或字符串创建BigInteger

@Test
public void whenBigIntegerCreatedFromConstructor_thenExpectedResult() {
    BigInteger biFromString = new BigInteger("1234567890987654321");
    BigInteger biFromByteArray = new BigInteger(
       new byte[] { 64, 64, 64, 64, 64, 64 });
    BigInteger biFromSignMagnitude = new BigInteger(-1,
       new byte[] { 64, 64, 64, 64, 64, 64 });

    assertEquals("1234567890987654321", biFromString.toString());
    assertEquals("70644700037184", biFromByteArray.toString());
    assertEquals("-70644700037184", biFromSignMagnitude.toString());
}

In addition, we can convert a long to BigInteger using the static method valueOf:

此外,我们可以使用静态方法valueOf:将一个long转换为BigInteger

@Test
public void whenLongConvertedToBigInteger_thenValueMatches() {
    BigInteger bi =  BigInteger.valueOf(2305843009213693951L);
        
    assertEquals("2305843009213693951", bi.toString());
}

6. Operations on BigInteger

6.对BigInteger的操作

Similar to int and long, BigInteger implements all the arithmetic and logical operations. But, it does not overload the operators.

intlong类似,BigInteger实现了所有算术和逻辑运算。但是,它不对运算符进行重载。

It also implements the corresponding methods from Math class: abs, min, max, pow, signum.

它还实现了Math类中的相应方法。abs, min, max, pow, signum

We compare the value of two BigIntegers using the compareTo method:

我们使用compareTo方法比较两个BigIntegers的值:

@Test
public void givenBigIntegers_whentCompared_thenExpectedResult() {
    BigInteger i = new BigInteger("123456789012345678901234567890");
    BigInteger j = new BigInteger("123456789012345678901234567891");
    BigInteger k = new BigInteger("123456789012345678901234567892");

    assertTrue(i.compareTo(i) == 0);
    assertTrue(j.compareTo(i) > 0);
    assertTrue(j.compareTo(k) < 0);
}

We perform arithmetic operations by calling the corresponding methods:

我们通过调用相应的方法进行算术运算:

@Test
public void givenBigIntegers_whenPerformingArithmetic_thenExpectedResult() {
    BigInteger i = new BigInteger("4");
    BigInteger j = new BigInteger("2");

    BigInteger sum = i.add(j);
    BigInteger difference = i.subtract(j);
    BigInteger quotient = i.divide(j);
    BigInteger product = i.multiply(j);

    assertEquals(new BigInteger("6"), sum);
    assertEquals(new BigInteger("2"), difference);
    assertEquals(new BigInteger("2"), quotient);
    assertEquals(new BigInteger("8"), product);
}

As BigInteger is immutable, these operations do not modify the existing objects. Unlike, int and long, these operations do not overflow.

由于BigInteger是不可变的,这些操作不会修改现有的对象。intlong不同,这些操作不会发生溢出。

BigInteger has the bit operations similar to int and long. But, we need to use the methods instead of operators:

BigInteger具有类似于intlong的位操作。但是,我们需要使用方法而不是运算符。

@Test
public void givenBigIntegers_whenPerformingBitOperations_thenExpectedResult() {
    BigInteger i = new BigInteger("17");
    BigInteger j = new BigInteger("7");

    BigInteger and = i.and(j);
    BigInteger or = i.or(j);
    BigInteger not = j.not();
    BigInteger xor = i.xor(j);
    BigInteger andNot = i.andNot(j);
    BigInteger shiftLeft = i.shiftLeft(1);
    BigInteger shiftRight = i.shiftRight(1);

    assertEquals(new BigInteger("1"), and);
    assertEquals(new BigInteger("23"), or);
    assertEquals(new BigInteger("-8"), not);
    assertEquals(new BigInteger("22"), xor);
    assertEquals(new BigInteger("16"), andNot);
    assertEquals(new BigInteger("34"), shiftLeft);
    assertEquals(new BigInteger("8"), shiftRight);
}

It has additional bit manipulation methods:

它有额外的位操作方法

@Test
public void givenBigIntegers_whenPerformingBitManipulations_thenExpectedResult() {
    BigInteger i = new BigInteger("1018");

    int bitCount = i.bitCount();
    int bitLength = i.bitLength();
    int getLowestSetBit = i.getLowestSetBit();
    boolean testBit3 = i.testBit(3);
    BigInteger setBit12 = i.setBit(12);
    BigInteger flipBit0 = i.flipBit(0);
    BigInteger clearBit3 = i.clearBit(3);

    assertEquals(8, bitCount);
    assertEquals(10, bitLength);
    assertEquals(1, getLowestSetBit);
    assertEquals(true, testBit3);
    assertEquals(new BigInteger("5114"), setBit12);
    assertEquals(new BigInteger("1019"), flipBit0);
    assertEquals(new BigInteger("1010"), clearBit3);
}

BigInteger provides methods for GCD computation and modular arithmetic:

BigInteger提供了GCD计算和模块化运算的方法

@Test
public void givenBigIntegers_whenModularCalculation_thenExpectedResult() {
    BigInteger i = new BigInteger("31");
    BigInteger j = new BigInteger("24");
    BigInteger k = new BigInteger("16");

    BigInteger gcd = j.gcd(k);
    BigInteger multiplyAndmod = j.multiply(k).mod(i);
    BigInteger modInverse = j.modInverse(i);
    BigInteger modPow = j.modPow(k, i);

    assertEquals(new BigInteger("8"), gcd);
    assertEquals(new BigInteger("12"), multiplyAndmod);
    assertEquals(new BigInteger("22"), modInverse);
    assertEquals(new BigInteger("7"), modPow);
}

It also has methods related to prime generation and primality testing:

它也有与素数生成和素数检验有关的方法

@Test
public void givenBigIntegers_whenPrimeOperations_thenExpectedResult() {
    BigInteger i = BigInteger.probablePrime(100, new Random());
        
    boolean isProbablePrime = i.isProbablePrime(1000);
    assertEquals(true, isProbablePrime);
}

7. Conclusion

7.结语

In this quick tutorial, we explored the classes BigDecimal and BigInteger. They are useful for advanced numerical computations where the primitive integer types do not suffice.

在这个快速教程中,我们探讨了BigDecimalBigInteger类。它们对于原始整数类型不能满足的高级数值计算非常有用。

As usual, the full source code can be found over on GitHub.

像往常一样,完整的源代码可以在GitHub上找到超过