将 double 舍入到小数点后 2 位

2022-01-30 00:00:00 rounding double java

如果值为200.3456,则应格式化为200.34.如果是200,那么应该是200.00.

If the value is 200.3456, it should be formatted to 200.34. If it is 200, then it should be 200.00.

推荐答案

这是一个实用程序,它四舍五入(而不是截断)一个双精度数到指定的小数位数.

Here's an utility that rounds (instead of truncating) a double to specified number of decimal places.

例如:

round(200.3456, 2); // returns 200.35

原版;小心这个

public static double round(double value, int places) {
    if (places < 0) throw new IllegalArgumentException();

    long factor = (long) Math.pow(10, places);
    value = value * factor;
    long tmp = Math.round(value);
    return (double) tmp / factor;
}

在小数位数非常多(例如 round(1000.0d, 17))或大整数部分(例如 <代码>圆形(90080070060.1d,9)).感谢 Sloin 指出这一点.

This breaks down badly in corner cases with either a very high number of decimal places (e.g. round(1000.0d, 17)) or large integer part (e.g. round(90080070060.1d, 9)). Thanks to Sloin for pointing this out.

多年来,我一直在使用上述方法将不太大"的双精度数四舍五入到小数点后 2 或 3 位(例如,为了记录目的,以秒为单位清理时间:27.987654321987 -> 27.99).但我想最好避免它,因为更可靠的方法很容易获得,而且代码也更简洁.

I've been using the above to round "not-too-big" doubles to 2 or 3 decimal places happily for years (for example to clean up time in seconds for logging purposes: 27.987654321987 -> 27.99). But I guess it's best to avoid it, since more reliable ways are readily available, with cleaner code too.

(改编自 Louis Wasserman 的这个答案 和 肖恩·欧文的这个.)

public static double round(double value, int places) {
    if (places < 0) throw new IllegalArgumentException();

    BigDecimal bd = BigDecimal.valueOf(value);
    bd = bd.setScale(places, RoundingMode.HALF_UP);
    return bd.doubleValue();
}

请注意,HALF_UP 是学校常教"的舍入模式.如果您怀疑自己,请仔细阅读 RoundingMode 文档需要其他东西,例如 Bankers' Rounding.

Note that HALF_UP is the rounding mode "commonly taught at school". Peruse the RoundingMode documentation, if you suspect you need something else such as Bankers’ Rounding.

当然,如果您愿意,您可以将上述内容内联到一个单行中:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()

Of course, if you prefer, you can inline the above into a one-liner:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()

永远记住,使用 floatdouble 的浮点表示是不精确.例如,考虑以下表达式:

Always remember that floating point representations using float and double are inexact. For example, consider these expressions:

999199.1231231235 == 999199.1231231236 // true
1.03 - 0.41 // 0.6200000000000001

为了准确起见,您想使用 BigDecimal.在此过程中,请使用带有 String 的构造函数,而不是使用 double 的构造函数.例如,尝试执行这个:

For exactness, you want to use BigDecimal. And while at it, use the constructor that takes a String, never the one taking double. For instance, try executing this:

System.out.println(new BigDecimal(1.03).subtract(new BigDecimal(0.41)));
System.out.println(new BigDecimal("1.03").subtract(new BigDecimal("0.41")));

有关该主题的一些出色的进一步阅读:

Some excellent further reading on the topic:

  • 第 48 项:如果需要准确答案,请避免使用 floatdouble"Effective Java(第二版),Joshua Bloch李>
  • 每个程序员都应该知道的浮点运算知识
  • Item 48: "Avoid float and double if exact answers are required" in Effective Java (2nd ed) by Joshua Bloch
  • What Every Programmer Should Know About Floating-Point Arithmetic

如果您想要 String formatting 而不是(或除了)严格舍入数字,请参阅其他答案.

If you wanted String formatting instead of (or in addition to) strictly rounding numbers, see the other answers.

特别注意 round(200, 0) 返回 200.0.如果你想输出200.00",你应该先四舍五入然后格式化输出结果(这在Jesper 的回答).

Specifically, note that round(200, 0) returns 200.0. If you want to output "200.00", you should first round and then format the result for output (which is perfectly explained in Jesper's answer).

相关文章