Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BigDecimal.add strange behavior

Method BigDecimal.add takes a long time when one argument has a big exponent (9 digits), and the second has an exponent with the different length. I've waited for more than 5 minutes, and it was still going on and on.

Here's code:

@Test
public void testAddBig() throws Exception {
    MathContext mc = new MathContext(10, RoundingMode.HALF_UP);
    BigDecimal v1 = new BigDecimal("1E+100000000", mc);
    BigDecimal v2 = new BigDecimal("1", mc);
    System.out.println(v1.add(v2));
}

Here's part of thread dump:

at java.math.BigInteger.square(BigInteger.java:1884)
at java.math.BigInteger.squareKaratsuba(BigInteger.java:1975)
at java.math.BigInteger.square(BigInteger.java:1888)
at java.math.BigInteger.squareToomCook3(BigInteger.java:2011)
at java.math.BigInteger.square(BigInteger.java:1890)
at java.math.BigInteger.squareToomCook3(BigInteger.java:2006)
at java.math.BigInteger.square(BigInteger.java:1890)
at java.math.BigInteger.squareToomCook3(BigInteger.java:2012)
at java.math.BigInteger.square(BigInteger.java:1890)
at java.math.BigInteger.squareToomCook3(BigInteger.java:2010)
at java.math.BigInteger.square(BigInteger.java:1890)
at java.math.BigInteger.squareToomCook3(BigInteger.java:2006)
at java.math.BigInteger.square(BigInteger.java:1890)
at java.math.BigInteger.squareToomCook3(BigInteger.java:2012)
at java.math.BigInteger.square(BigInteger.java:1890)
at java.math.BigInteger.squareToomCook3(BigInteger.java:2011)
at java.math.BigInteger.square(BigInteger.java:1890)
at java.math.BigInteger.pow(BigInteger.java:2263)
at java.math.BigDecimal.bigTenToThe(BigDecimal.java:3543)
at java.math.BigDecimal.bigMultiplyPowerTen(BigDecimal.java:4508)
at java.math.BigDecimal.add(BigDecimal.java:4443)
at java.math.BigDecimal.add(BigDecimal.java:1289)

What is going on? Is this a bug?

like image 728
VMN Avatar asked Nov 08 '16 12:11

VMN


1 Answers

Well, to answer this simply. BigNumbers are working with array of character to keep the precision at the maximum. Since you number will be composed of 100000000 digits, this will be the length of your array.

100.000.000 chars = bytes

This is 100MB if I am not mistaken. Then you want to do math with that, this start to be a lot of reading ;)

If you open the BigDecimal class, you will see that there is a lot of checks since this is "letter" and not numbers.

BigDecimal are usefull to keep precision but this is done at some cost, here memory and time of processing.

EDIT :

This will only be a problem if you use the instance in some ways, the constructor will store the value as a exponent value 1E+***. If you print it this will be fine but if you ask a numerical value, this will start to failed.

To be more precise, BigDecimal.bigTenToThe(int) will receive the exponent value (1000000000).

private static BigInteger bigTenToThe(int n) {
    ...
    char tenpow[] = new char[n + 1];
    ....
}
like image 81
AxelH Avatar answered Nov 05 '22 17:11

AxelH