这是一个实用程序,它四舍五入(而不是截断)一个双精度数到指定的小数位数。
例如:
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))或大整数部分(例如round(90080070060.1d, 9))的极端情况下,这严重崩溃。感谢Sloin 指出这一点。
多年来,我一直在使用上述方法将“不太大”的双精度数四舍五入到小数点后 2 或 3 位(例如,为了记录目的,以秒为单位清理时间:27.987654321987 -> 27.99)。但我想最好避免它,因为更可靠的方法很容易获得,而且代码也更简洁。
所以,改用这个
(改编自this answer by Louis Wasserman和this one by Sean Owen。)
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 是“学校常教”的舍入模式。如果您怀疑自己需要其他内容,例如 Bankers’ Rounding,请仔细阅读 RoundingMode documentation。
当然,如果您愿意,也可以将上述内容内联成一个单行:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()
在任何情况下
永远记住,使用float 和double 的浮点表示是不精确的。
例如,考虑以下表达式:
999199.1231231235 == 999199.1231231236 // true
1.03 - 0.41 // 0.6200000000000001
For exactness, you want to use BigDecimal。在此过程中,请使用带有 String 的构造函数,而不是使用 double 的构造函数。例如,尝试执行这个:
System.out.println(new BigDecimal(1.03).subtract(new BigDecimal(0.41)));
System.out.println(new BigDecimal("1.03").subtract(new BigDecimal("0.41")));
有关该主题的一些出色的进一步阅读:
如果您想要 String formatting 而不是(或除此之外)严格舍入数字,请参阅其他答案。
具体来说,请注意round(200, 0) 返回200.0。如果你想输出“200.00”,你应该先四舍五入然后格式化输出结果(这在Jesper's answer中有完美的解释)。