Почему метод scale () для bigDecimal возвращает отрицательное значение при объединении с методом stripTrailingZeros ()? - PullRequest
3 голосов
/ 04 апреля 2019

Чтобы избежать значения, например, 10,0000 для BigDecimal, я использовал метод stripTrailingZeros(), который возвращает значение 10 вместо 10,0000, как ожидалось. Теперь шкала 10 должна быть 0, потому что для нуля или положительного значения шкала - это количество цифр справа от десятичной точки. Тем не менее, это не так, поскольку он возвращает -1.

Log.d("click", BigDecimal("10").toPlainString()) // return 10
Log.d("click", BigDecimal("10").stripTrailingZeros().toPlainString()) // return 10

При возврате кода выше одно и то же значение 10 и stripTrailingZeros() не влияет на их значение.

Log.d("click", BigDecimal("10").scale().toString())  // return 0
Log.d("click", BigDecimal("10").stripTrailingZeros().scale().toString()) // return -1

Но масштаб этих значений отличается, так как он возвращает 0 и -1, а также

Log.d("click", BigDecimal("100").stripTrailingZeros().scale().toString()) // return -2
Log.d("click", BigDecimal("1000").stripTrailingZeros().scale().toString()) // return -3

Есть ли способ получить ожидаемый результат? Кто-нибудь может объяснить, почему scale() метод возвращает отрицательное значение?

1 Ответ

0 голосов
/ 04 апреля 2019

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

unscaledValue и scale

Большие десятичные числа могут помнить количество десятичных знаков (мест после десятичного разделителя), которое оно имеет.Для этого они сохраняются в виде двух значений:

  • и unscaledValue (обычно это BigInteger, но для небольших значений это тоже может быть long), которое содержит (значительный) цифры и
  • a масштаб ( минус степень 10 для умножения unscaledValue на, чтобы получить номинальное значение , то есть вид отрицательного показателя).

Примеры: значение 1.0 хранится в виде UnscaledValue (я назову его UV) 10 и шкалы 1 ( 10 x 10 -1 ).Значение 3.000 сохраняется как УФ 3000 и шкала 3 ( 3000 x 10 -3 ), 12.34 как УФ= 1234 и шкала = 2 (т. Е. 1234 x 10 -2 ) и т. Д.

Ваше значение 10 сохраняется как UV = 10 и масштаб = 0 (кратко: UV = 10, s = 0).Но если вы удаляете конечные нули, вы конвертируете, например, 1.000 (UV = 1000, S = 3), вы удаляете пробные нули из UV и соответственно корректируете масштаб, чтобы он стал (UV = 1, S= 0): УФ теряет 3 нуля, шкала настраивается на 0.

Можно также использовать отрицательные шкалы , чтобы обозначить ( положительная ) степень 10.значение 2e20 сохраняется как UV = 2, с = -20 ( 2 x 10 20 ), а не как UV = 200000000000000000000, с = 0.Это экономит много места.Точно так же 2.00e20 сохраняется как UV = 200, с = -18 или 200 x 10 18 .

. Поэтому,при удалении конечных нулей 10 становится UV = 1, с = -1 ( 1 x 10 1 ) вместо UV = 10, s = 0( 10 x 10 0 ).И 6000 (УФ = 6000, с = 0) становится 6Е + 3 (УФ = 6, с = -3; 6 х 10 3 ).

Установка шкалы

Но вы можете легко установить шкалу обратно на 0 без изменения номинального значения.Если шкала была отрицательной, округление не произойдет.

BigDecimal b1 = new BigDecimal("10.000"); // UV=10000, s=3, 10000 x 10**-3
System.out.println(b1);
b1 = b1.stripTrailingZeros();             // UV=1, s=-1, *all* trailing zeros removed,
                                          // as desired: 10000 --> 1
System.out.println(b1);
b1 = b1.setScale(0);                      // UV=10, s=0
System.out.println(b1);

Вывод:

10.000
1E+1
10

Чтобы удалить только конечные десятичные нули, выполните:

b1 = b1.stripTrailingZeros();
if (b1.scale() < 0)
  b1 = b1.setScale(0);
...