最近我尝试理解java.math.MathContext的使用但未能正确理解。是否用于四舍五入java.math.BigDecimal
。如果是,为什么不四舍五入十进制数字,甚至尾数部分。
从 API 文档中,我了解到它遵循和规范中指定的标准,ANSI X3.274-1996
但ANSI X3.274-1996/AM 1-2000
我没有让它们在线阅读。
如果您对此有任何想法,请告诉我。
最近我尝试理解java.math.MathContext的使用但未能正确理解。是否用于四舍五入java.math.BigDecimal
。如果是,为什么不四舍五入十进制数字,甚至尾数部分。
从 API 文档中,我了解到它遵循和规范中指定的标准,ANSI X3.274-1996
但ANSI X3.274-1996/AM 1-2000
我没有让它们在线阅读。
如果您对此有任何想法,请告诉我。
要仅舍入 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(由于向上舍入规则)
@jatan
谢谢你的回答。这说得通。您能否在 BigDecimal#round 方法的上下文中解释一下 MathContext。
BigDecimal.round()
与任何其他BigDecimal
方法相比,没有什么特别之处。在所有情况下,MathContext
指定有效位数和舍入技术。基本上,每个MathContext
. 有精度,也有RoundingMode
.
精度再次指定有效位数。因此,如果您指定123
为一个数字,并要求 2 个有效数字,您将得到120
. 如果你用科学记数法来思考可能会更清楚。
123
将采用1.23e2
科学计数法。如果您只保留 2 位有效数字,那么您会得到1.2e2
或120
。通过减少有效数字的数量,我们可以降低指定数字的精度。
该RoundingMode
部分指定了我们应该如何处理精度损失。要重用该示例,如果您使用123
作为数字,并要求 2 个有效数字,则您降低了精度。使用RoundingMode
of HALF_UP
(默认模式),123
将变为120
. 使用RoundingMode
of 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
您可以看到精度和舍入模式都会影响输出。
我想在这里补充几个例子。我在以前的答案中没有找到它们,但我发现它们对于那些可能用小数位数误导有效数字的人很有用。假设,我们有这样的上下文:
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
所以我认为这是一种较新的技术,并将其用于舍入目的。然而,它变成了噩梦,因为它甚至开始舍入数字的 mentissa 部分。
例如,
Number = 1.5294
四舍五入为1.5
Number = 10.5294
四舍五入为10
Number = 101.5294
四舍五入为100
.... 等等
所以这不是我期望的舍入行为(因为精度 = 2)。
它似乎有一些逻辑,因为从模式我可以说它需要数字的前两位(因为精度为 2),然后附加 0 直到没有。位数变得与未四舍五入的数量相同(查看 101.5294 的示例 ...)