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

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

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

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
54
0
75 119
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

Спасибо. Как выбрать количество цифр после запятой?

Drew 08.03.2012 02:13

Это не совсем вопрос для BigDecimal. При использовании BigDecimal вместо этого следует указывать количество значащих цифр. Сколько цифр после десятичной точки следует определить при форматировании для отображения. Вы можете контролировать это с помощью String.format () или DecimalFormat.format ().

Derek Park 09.03.2012 22:48

@Drew Я думаю, вы можете использовать для этого метод BigDecimal.setScale. Первый параметр (масштаб) указывает, сколько чисел вы хотите сохранить после десятичной точки, а второй параметр (roundingMode) указывает желаемое поведение округления.

Quazi Irfan 21.01.2018 09:59

@Drew Здесь - это ответ, который объясняет это более подробно.

Quazi Irfan 21.01.2018 15:39

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

так что вы можете предложить вместо этого решение?

Sumit Ramteke 19.02.2014 10:55
Ответ принят как подходящий

@jatan

Thanks for you answer. It makes sense. Can you please explain me MathContext in the context of BigDecimal#round method.

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

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

123 будет 1.23e2 в научном представлении. Если вы сохраните только 2 значащие цифры, вы получите 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

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

Есть ли способ отформатировать 123.4 с использованием 2 значащих цифр, чтобы получить строку типа 120? Это две значащие цифры (как и 1.2E2), потому что конечные нули обычно не включаются при извлечении значащих цифр, если нет конечной десятичной дроби. И для моих целей, если число, которое нужно отформатировать, было 103.4, меня не волнует, что вы не можете сказать, что в полученном номере 100 есть 2 сигнатуры. Я просто хочу более простой / чистый просмотр чисел.

hepcat72 07.02.2017 18:00

Чтобы округлить дробную часть 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 (из-за правила округления).

Это тот ответ, которого хотят люди, работая с фиксированными десятичными числами и сохраняя фиксированное количество десятичных знаков. Не знаю, почему Sun напутала здесь с «точностью» в стиле с плавающей запятой, но это то, что такое MathContext.

Thomas W 28.04.2013 05:39

Это даже работает для округления BigDecimal без дробной части: original.setScale(0, RoundingMode.HALF_UP);

Tobias Otto 20.01.2021 20:03

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

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 значащие цифры, которое в данном случае равно «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

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

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