Вопрос

Недавно я попытался понять использование java.math.MathContext но не смог правильно понять.Используется ли он для округления java.math.BigDecimal.Если да, то почему не округляются десятичные цифры, а даже часть мантиссы.

Из документации API я узнал, что он соответствует стандарту, указанному в ANSI X3.274-1996 и ANSI X3.274-1996/AM 1-2000 спецификации, но мне не удалось их прочитать в Интернете.

Пожалуйста, дайте мне знать, если у вас есть идеи по этому поводу.

Это было полезно?

Решение

@jatan

Спасибо за ответ.Это имеет смысл.Не могли бы вы объяснить мне MathContext в контексте метода BigDecimal#round.

В этом нет ничего особенного BigDecimal.round() против. любой другой BigDecimal метод.Во всех случаях MathContext определяет количество значащих цифр и метод округления.По сути, каждый состоит из двух частей. MathContext.Есть точность, а есть еще RoundingMode.

Точность снова определяет количество значащих цифр.Итак, если вы укажете 123 как число и попросите две значащие цифры, вы получите 120.Возможно, будет яснее, если подумать в терминах научной записи.

123 было бы 1.23e2 в научной записи.Если вы сохраните только 2 значащие цифры, то вы получите 1.2e2, или 120.Уменьшая количество значащих цифр, мы уменьшаем точность, с которой мы можем указать число.

А RoundingMode часть определяет, как нам следует справляться с потерей точности.Чтобы повторно использовать пример, если вы используете 123 как число и запросите две значащие цифры, вы снизили точность.С RoundingMode из HALF_UP (режим по умолчанию), 123 станет 120RoundingMode из CEILING, ты получишь 130.

Например:

System.out.println(new BigDecimal("123.4",
                   new MathContext(4,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
                   new MathContext(2,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
                   new MathContext(2,RoundingMode.CEILING)));
System.out.println(new BigDecimal("123.4",
                   new MathContext(1,RoundingMode.CEILING)));

Выходы:

123.4
1.2E+2
1.3E+2
2E+2

Вы можете видеть, что на результат влияют как точность, так и режим округления.

Другие советы

Чтобы округлить только дробную часть BigDecimal, проверьте BigDecimal.setScale(int newScale, int roundingMode) метод.

Например.чтобы изменить число с тремя цифрами после запятой на число с двумя цифрами и округлением вверх:

BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);

Результатом этого является BigDecimal со значением 1,24 (из-за правила округления).

Я бы добавил сюда несколько примеров.Я не нашел их в предыдущих ответах, но считаю их полезными для тех, кто может вводить в заблуждение. значащие цифры с количеством десятичные знаки.Предположим, у нас есть такой контекст:

MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);

Для этого кода:

BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);

совершенно ясно, что ваш результат 1.23E+3 как ребята сказали выше.Первые значащие цифры 123...

Но что в данном случае:

BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);

твой номер не будет округляться до 3 знаков после запятой - для кого-то это может быть не интуитивно понятно и стоит подчеркнуть.Вместо этого оно будет округлено до первые 3 значащие цифры, в данном случае это «4 5 4».Таким образом, приведенный выше код приводит к 4.55E-7 и не в 0.000 как кто-то мог ожидать.

Похожие примеры:

BigDecimal d3 = new BigDecimal(0.001000045477, MATH_CTX);
 System.out.println(d3);  // 0.00100

BigDecimal d4 = new BigDecimal(0.200000477, MATH_CTX);
 System.out.println(d4);   // 0.200

BigDecimal d5 = new BigDecimal(0.000000004, MATH_CTX);
    System.out.println(d5); //4.00E-9

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

Если я вас правильно понимаю, похоже, вы ожидаете, что MathContext будет контролировать, сколько цифр должно оставаться после десятичной точки.Это не для этого.Он указывает, сколько цифр следует сохранить, общий.Поэтому, если вы укажете, что вам нужны 3 значащие цифры, это все, что вы получите.

Например, это:

System.out.println(new BigDecimal("1234567890.123456789",
                   new MathContext(20)));

System.out.println(new BigDecimal("1234567890.123456789",
                   new MathContext(10)));

System.out.println(new BigDecimal("1234567890.123456789",
                   new MathContext(5)));

выведет:

1234567890.123456789
1234567890
1.2346E+9

Это не для развлечения.На самом деле я нашел в Интернете пример, в котором указано использование MathContext для округления сумм/числ, хранящихся в BigDecimal.

Например,

Если MathContext настроен так, чтобы иметь precision = 2 и rounding mode = ROUND_HALF_EVEN

BigDecimal Number = 0.5294, является округлый к 0.53

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

Например,

Number = 1.5294 округляется до 1.5

Number = 10.5294 округляется до 10

Number = 101.5294 округляется до 100

....и так далее

Так что это не то поведение, которое я ожидал от округления (поскольку точность = 2).

Кажется, в этом есть некоторая логика, потому что по шаблону я могу сказать, что он берет первые две цифры (поскольку точность равна 2) числа, а затем добавляет 0 до номера.цифр становится таким же, как неокругленная сумма (проверьте пример 101,5294...)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top