2008-08-11 5 views
42

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

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

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

ответ

35

@jatan

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

Там нет ничего особенного BigDecimal.round()VS. любого другого 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 

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

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 
+1

Спасибо. Как я могу выбрать, сколько цифр нужно сохранить после десятичного числа? – Drew 2012-03-07 22:13:17

+1

Это не вопрос BigDecimal. С BigDecimal вы должны указывать количество значащих цифр. Сколько цифр после десятичной точки следует определять при форматировании для отображения. Вы можете управлять этим с помощью String.format() или DecimalFormat.format(). – 2012-03-09 18:48:51

+0

@Drew Я думаю, вы можете использовать [BigDecimal.setScale] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/math/BigDecimal.java# BigDecimal.setScale% 28int% 2Cjava.math.RoundingMode% 29) метод для него. Первый параметр (масштаб) определяет количество чисел, которые вы хотите сохранить после десятичной точки, а второй параметр (roundingMode) определяет требуемое поведение округления. – 2018-01-21 06:59:32

4

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

52

Для округления только дробной части BigDecimal ознакомьтесь с методом BigDecimal.setScale(int newScale, int roundingMode).

E.g. изменить число с помощью трех цифр после запятой в один с двумя цифрами, и округление:

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

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

9

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

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 

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