Подтвердить что ты не робот

Использование java.math.MathContext

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

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

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

4b9b3361

Ответ 1

@jatan

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

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

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

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

Часть RoundingMode указывает, как мы должны справляться с потерей точности. Чтобы повторно использовать пример, если вы используете 123 в качестве номера и запрашиваете 2 значащих цифры, вы уменьшили свою точность. При RoundingMode HALF_UP (режим по умолчанию) 123 станет 120. С помощью RoundingMode 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

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

Ответ 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 (из-за правила округления)

Ответ 3

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

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

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

Ответ 4

Если я правильно понимаю вас, похоже, вы ожидаете, что 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

Ответ 5

Это не для удовольствия. Фактически я нашел несколько онлайн-примеров, в которых говорилось об использовании 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).

Кажется, что у вас есть какая-то логика, потому что из-за patter я могу сказать, что первые две цифры (как точность 2) числа, а затем добавляются 0 до no. цифр становятся такими же, как и неосновная сумма (проверьте пример 101.5294...)