2016-11-08 6 views
13

Метод BigDecimal.add занимает много времени, когда один аргумент имеет большой показатель (9 цифр), а второй имеет экспонента с разной длиной. Я ждал более 5 минут, и все продолжалось.BigDecimal.add странное поведение

Вот код:

@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)); 
} 

Вот часть потока отвала:

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) 

Что происходит? Это ошибка?

+0

Вы запрашиваете здесь огромное количество. На VM у меня был OutOfMemoryError из-за этого;) Просто сделайте это в калькуляторе windows;) Это даст мне мышей Invalid Imput. Это дает вам представление о длине этого числа. – AxelH

+2

@VMN: Знаете ли вы, что означает '1E + 100000000'? – Axel

+0

Плюс, есть этот комментарий в bigTenToThe BigInteger.pow медленный, поэтому сделайте 10 ** n, построив BigInteger из символьной строки (все еще не очень быстро) 'используя char [] размера вашего номера (не маленький ...) Поэтому не ожидайте, что сможете быстро использовать BigNumbers. – AxelH

ответ

7

Ну, чтобы ответить на это просто. BigNumbers работают с массивом символов, чтобы обеспечить максимальную точность. Поскольку ваш номер будет состоять из 100000000 цифр, это будет длина вашего массива.

100.000.000 симв = байт

Это 100MB, если я не ошибаюсь. Затем вы хотите сделать математику с этим, это начало много читать;)

Если вы откроете класс BigDecimal, вы увидите, что существует множество проверок, поскольку это «буква», а не цифры.

BigDecimal полезны для сохранения точности, но это делается за небольшую плату, здесь память и время обработки.

EDIT:

Это будет только проблема, если вы используете экземпляр в каком-то смысле, конструктор будет хранить значение в качестве значения показателя 1E + ***. Если вы распечатаете это, это будет нормально, но если вы попросите числовое значение, это начнет сбой.

Чтобы быть более точным, BigDecimal.bigTenToThe(int) получит значение экспоненты (1000000000).

private static BigInteger bigTenToThe(int n) { 
    ... 
    char tenpow[] = new char[n + 1]; 
    .... 
} 
+0

Mm, внутреннее представление выглядит как (intCompact = 1, scale = -10000000, precision = 1) Нет 100.000.000 символов – VMN

+0

@VMN Пока вы не освоите математику. Я добавил дополнительную информацию, увидев трассировку стека, вы увидите метод, о котором я говорил. – AxelH

+0

Спасибо, я понял. В моей версии jdk (1.8.72) 'int [] mag' используется внутри' BigInteger', но этот факт не сильно меняется. – VMN