使用java.math.MathContext

jat*_*anp 48 java math bigdecimal mathcontext

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

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

如果您对此有任何想法,请告诉我.

Øys*_*ebø 66

要仅舍入BigDecimal的小数部分,请查看BigDecimal.setScale(int newScale, int roundingMode)方法.

例如,将小数点后的三位数字更改为两位数的数字,并向上舍入:

BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);
Run Code Online (Sandbox Code Playgroud)

结果是BigDecimal值为1.24(因为舍入规则)

  • 这是人们想要的答案,使用固定十进制数并保持固定的小数位数.不知道为什么Sun在这里捏造了浮点式"精确",但这就是MathContext的意思. (15认同)

Der*_*ark 44

@jatan

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

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

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

123将采用1.23e2科学记数法.如果你只保留2位有效数字,那么你得到1.2e2,或120.通过减少有效位数,我们降低了指定数字的精度.

RoundingMode部分规定了我们应该如何处理精度损失.要重复使用该示例,如果您使用123数字,并要求2位有效数字,则会降低精度.用RoundingModeHALF_UP(默认模式),123将成为120.用RoundingModeCEILING,你会得到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)));
Run Code Online (Sandbox Code Playgroud)

输出:

123.4
1.2E+2
1.3E+2
2E+2
Run Code Online (Sandbox Code Playgroud)

您可以看到精度和舍入模式都会影响输出.


gui*_*eak 13

我想在这里添加一些例子.我还没有发现他们在以前的答案,但我觉得他们对于那些谁可能误导有用显著数字与数位小数.我们假设,我们有这样的背景:

MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);
Run Code Online (Sandbox Code Playgroud)

对于此代码:

BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);
Run Code Online (Sandbox Code Playgroud)

很明显,你的结果1.23E+3就像上面提到的那样.首字母是123 ...

但在这种情况下:

BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);
Run Code Online (Sandbox Code Playgroud)

你的号码在逗号后不会四舍五入 - 对某些人来说,这可能不直观,值得强调.相反,它将四舍五入到前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
Run Code Online (Sandbox Code Playgroud)

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


Der*_*ark 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)));
Run Code Online (Sandbox Code Playgroud)

将输出:

1234567890.123456789
1234567890
1.2346E+9
Run Code Online (Sandbox Code Playgroud)


jat*_*anp 5

这不是为了好玩。实际上,我找到了一些在线示例,其中说明了对MathContextBigDecimal 中存储的金额/数字进行四舍五入的用法。

例如,

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

BigDecimal Number = 0.5294四舍五入0.53

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

例如,

Number = 1.5294 四舍五入为 1.5

Number = 10.5294 四舍五入为 10

Number = 101.5294 四舍五入为 100

.... 等等

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

它似乎有一些逻辑,因为从模式我可以说它需要数字的前两位数(因为精度是 2),然后附加 0 直到没有。数字变得与未四舍五入的数量相同(查看 101.5294 的示例...)

  • 所以你也可以建议替代解决方案吗? (2认同)