java.math.MathContext 的使用
-
08-06-2019 - |
题
最近我尝试了解使用 java.math.MathContext 但未能正确理解。是否用于舍入 java.math.BigDecimal
. 。如果是的话,为什么它不四舍五入小数位,甚至尾数部分。
从API文档中,我了解到它遵循中指定的标准 ANSI X3.274-1996
和 ANSI X3.274-1996/AM 1-2000
规格,但我没有让它们在线阅读。
如果您对此有任何想法,请告诉我。
解决方案
@jatan
谢谢你的回答。这说得通。您能在 BigDecimal#round 方法的上下文中向我解释一下 MathContext 吗?
没什么特别的 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
您可以看到精度和舍入模式都会影响输出。
其他提示
要仅舍入 BigDecimal 的小数部分,请查看 BigDecimal.setScale(int newScale, int roundingMode)
方法。
例如。将小数点后三位数字更改为两位数,并向上舍入:
BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);
结果是一个值为 1.24 的 BigDecimal(由于向上舍入规则)
我想在这里添加几个例子。我在以前的答案中没有找到它们,但我发现它们对于那些可能误导的人很有用 有效数字 与数量 小数位. 。假设我们有这样的上下文:
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
我希望这个显而易见但相关的例子会有所帮助......
如果我理解正确的话,听起来您希望 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
这不是为了好玩。其实我在网上找到了一些例子,其中说明了使用 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 直到数字。位数与未四舍五入的金额相同(查看 101.5294 ... 的示例)