简体   繁体   English

java.math.RoundingMode 是如何工作的?

[英]how does java.math.RoundingMode work?

I'm having trouble with rounding.我在四舍五入时遇到问题。 Specifically, after reading all the javadoc, I was expecting the following code:具体来说,在阅读了所有 javadoc 之后,我期待以下代码:

int n = (integer between 0 and 9, included)
new BigDecimal(n + 0.555d).setScale(2, RoundingMode.HALF_UP).doubleValue()

to return n + 0.56 .返回n + 0.56 Instead, these are the return values for n from 0 to 4 :相反,这些是n04的返回值:

 new BigDecimal(0.555d).setScale(2, RoundingMode.HALF_UP).doubleValue()
 0.56
 new BigDecimal(1.555d).setScale(2, RoundingMode.HALF_UP).doubleValue()
 1.55
 new BigDecimal(2.555d).setScale(2, RoundingMode.HALF_UP).doubleValue()
 2.56
 new BigDecimal(3.555d).setScale(2, RoundingMode.HALF_UP).doubleValue()
 3.56
 new BigDecimal(4.555d).setScale(2, RoundingMode.HALF_UP).doubleValue()
 4.55

I have also tried to change the rounding mode:我还尝试更改舍入模式:

int n = (integer between 0 and 9, included)
new BigDecimal(n + 0.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue()

expecting n + 0.55 as a result for each and every n .期望n + 0.55作为每个n的结果。 Instead, the return values are exactly the same as the previous example:相反,返回值与前面的示例完全相同:

 new BigDecimal(0.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue()
 0.56
 new BigDecimal(1.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue()
 1.55
 new BigDecimal(2.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue()
 2.56
 new BigDecimal(3.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue()
 3.56
 new BigDecimal(4.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue()
 4.55

Am I missing something?我错过了什么吗?

The problem you have is that double is not a precise representation and you are round based on this imprecise number.你遇到的问题是 double 不是一个精确的表示,你是基于这个不精确的数字进行舍入的。

BigDecimal bd = new BigDecimal(1.555d);
System.out.println("bd=" + bd);
bd = bd.setScale(2, RoundingMode.HALF_UP);
System.out.println("after rounding bd=" + bd);
double d = bd.doubleValue();
System.out.println("after rounding d=" + d);

prints印刷

bd=1.5549999999999999378275106209912337362766265869140625
after rounding bd=1.55
after rounding d=1.55

however然而

BigDecimal bd = BigDecimal.valueOf(1.555d);
System.out.println("bd=" + bd);
bd = bd.setScale(2, RoundingMode.HALF_UP);
System.out.println("after rounding bd=" + bd);
double d = bd.doubleValue();
System.out.println("after rounding d=" + d);

prints印刷

bd=1.555
after rounding bd=1.56
after rounding d=1.56

This works because BigDecimal.valueOf does some extra rounding based on how double would appear if you printed it.这是有效的,因为BigDecimal.valueOf会根据打印时出现的 double 情况进行一些额外的舍入。


However I wouldn't use BigDecimal unless performance/simplicity is not an issue.但是,除非性能/简单性不是问题,否则我不会使用 BigDecimal。

double d = 1.555d;
System.out.println("d=" + d);
d = roundToTwoPlaces(d);
System.out.println("after rounding d=" + d);

public static double roundToTwoPlaces(double d) {
    return ((long) (d < 0 ? d * 100 - 0.5 : d * 100 + 0.5)) / 100.0;
}

prints印刷

d=1.555
after rounding d=1.56

For more details Double your money again compares the performance of different ways of rounding.详细信息Double your money again比较不同四舍五入方式的性能。

@Peter Lawrey I looked at your examples and wrote a quick program comparing the simple approach that you posted along with all the methods for RoundingMode. @Peter Lawrey 我查看了您的示例并编写了一个快速程序,比较了您发布的简单方法以及 RoundingMode 的所有方法。 The code is here for anyone interested, this will clearly show the differences:代码在这里供任何感兴趣的人使用,这将清楚地显示差异:

[RoundingMode.java] https://gitlab.com/bobby.estey/java/-/blob/master/maven/jdk14/src/main/java/mathematics/RoundingModeExamples.java [RoundingMode.java] https://gitlab.com/bobby.estey/java/-/blob/master/maven/jdk14/src/main/java/mathematics/RoundingModeExamples.java

Results:
lowDouble:                             1.55553
simple - lowDouble:                    1.5555
RoundingMode.UP - lowDouble:           1.5556
RoundingMode.DOWN - lowDouble:         1.5555
RoundingMode.CEILING - lowDouble:      1.5556
RoundingMode.FLOOR - lowDouble:        1.5555
RoundingMode.HALF_UP - lowDouble:      1.5555
RoundingMode.HALF_DOWN - lowDouble:    1.5555
RoundingMode.HALF_EVEN - lowDouble:    1.5555
highDouble:                            1.55555
simple - highDouble:                   1.5556
RoundingMode.UP - highDouble:          1.5556
RoundingMode.DOWN - highDouble:        1.5555
RoundingMode.CEILING - highDouble:     1.5556
RoundingMode.FLOOR - highDouble:       1.5555
RoundingMode.HALF_UP - highDouble:     1.5555
RoundingMode.HALF_DOWN - highDouble:   1.5555
RoundingMode.HALF_EVEN - highDouble:   1.5555

0.555d is a double value. 0.555d是一个double 0.555d值。 It may be slightly larger than 0.555 or slightly smaller.它可能略大于 0.555 或略小。

Rounding mode use for Round the Decimal Value.舍入模式用于舍入十进制值。

You can use with.您可以使用。

double DecimalValue = 3.1452;
BigDecimal decimal = new BigDecimal(DecimalValue).setScale(2, RoundingMode.DOWN);

=> =>

 RoundingMode.CEILING

Rounding mode to round towards positive infinity.向正无穷大舍入的舍入模式。 For positive values this rounding mode behaves as UP, for negative values as DOWN.对于正值,此舍入模式表现为向上,对于负值表现为向下。 Rule: x.round() >= x规则: x.round() >= x

RoundingMode.DOWN

Rounding mode where the values are rounded towards zero.值向零舍入的舍入模式。 Rule: x.round().abs() <= x.abs()规则: x.round().abs() <= x.abs()

RoundingMode.DOWN

Rounding mode to round towards negative infinity.向负无穷大舍入的舍入模式。 For positive values this rounding mode behaves as DOWN, for negative values as UP.对于正值,此舍入模式表现为 DOWN,对于负值表现为 UP。 Rule: x.round() <= x规则: x.round() <= x

RoundingMode.HALF_DOWN

Rounding mode where values are rounded towards the nearest neighbor.舍入模式,其中值向最近的邻居舍入。 Ties are broken by rounding down.通过四舍五入打破平局。

RoundingMode.HALF_EVEN

Rounding mode where values are rounded towards the nearest neighbor.舍入模式,其中值向最近的邻居舍入。 Ties are broken by rounding to the even neighbor.通过四舍五入到偶数邻居来打破平局。

RoundingMode.HALF_UP

Rounding mode where values are rounded towards the nearest neighbor.舍入模式,其中值向最近的邻居舍入。 Ties are broken by rounding up.通过四舍五入打破平局。

 RoundingMode.UNNECESSARY

Rounding mode where the rounding operations throws an ArithmeticException for the case that rounding is necessary, ie for the case that the value cannot be represented exactly.舍入模式,其中舍入操作会在需要舍入的情况下引发ArithmeticException ,即无法准确表示值的情况。

RoundingMode.UP

Rounding mode where positive values are rounded towards positive infinity and negative values towards negative infinity.舍入模式,正值向正无穷大舍入,负值向负无穷大舍入。 Rule: x.round().abs() >= x.abs()规则: x.round().abs() >= x.abs()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM