使用java.math.MathContext

时间:2008-08-11 05:23:02

标签: java math bigdecimal mathcontext

最近我尝试了解 java.math.MathContext 的使用,但未能正确理解。它是否用于java.math.BigDecimal中的舍入。如果是,为什么不围绕十进制数字,甚至是尾数部分。

从API文档中,我发现它遵循ANSI X3.274-1996ANSI X3.274-1996/AM 1-2000规范中指定的标准,但我没有让它们在线阅读。

如果您对此有任何疑问,请与我们联系。

5 个答案:

答案 0 :(得分:59)

要仅舍入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(因为舍入规则)

答案 1 :(得分:40)

@jatan

  

谢谢你的回答。这说得通。你能否在BigDecimal#round方法的上下文中解释我MathContext。

BigDecimal.round() vs。任何其他BigDecimal方法都没有什么特别之处。在所有情况下,MathContext指定有效位数和舍入技术。基本上,每MathContext有两部分。有精确度,还有RoundingMode

精度再次指定有效位数。因此,如果您将123指定为数字,并要求输入2位有效数字,那么您将获得120。如果你从科学记数的角度思考,可能会更清楚。

科学记谱法中{p> 1231.23e2。如果您只保留2位有效数字,则会获得1.2e2120。通过减少有效位数,我们降低了指定数字的精度。

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 :(得分:12)

我想在这里添加一些例子。我还没有在以前的答案中找到它们,但我发现它们对于那些可能误导有效数字小数位数的人有用。让我们假设,我们有这样的背景:

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

我希望这显而易见,但相关的例子会有所帮助......

答案 3 :(得分: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

答案 4 :(得分:4)

这不是为了好玩。实际上我发现了一些在线示例,其中说明使用MathContext来舍入存储在BigDecimal中的金额/数字。

例如,

如果MathContext配置为precision = 2rounding mode = ROUND_HALF_EVEN

BigDecimal Number = 0.5294舍入 0.53

所以我认为这是一种较新的技术,并将其用于舍入目的。然而它变成了噩梦,因为它甚至开始绕过数字的一部分。#/ p>

例如,

Number = 1.5294四舍五入为1.5

Number = 10.5294四舍五入为10

Number = 101.5294四舍五入为100

....等等

所以这不是我期望的四舍五入的行为(因为precision = 2)。

它似乎有一些逻辑,因为从模式我可以说它需要数字的前两位数(精度是2)然后追加0直到no。数字与未包含的数量相同(结帐101.5294的例子......)