我想要的是一种将双精度转换为字符串的方法,该字符串使用半向上舍入方法进行舍入-即,如果要舍入的小数为5,则始终向上舍入到下一个数字。这是大多数人在大多数情况下所期望的四舍五入的标准方法。

我还希望只显示有效数字,即不应有任何尾随零。

我知道这样做的一种方法是使用String.format方法:

String.format("%.5g%n", 0.912385);

返回:

0.91239

这是很好的,但是它总是显示带有5位小数的数字,即使它们不重要:

String.format("%.5g%n", 0.912300);

返回:

0.91230

另一种方法是使用DecimalFormatter:

DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);

返回:

0.91238

然而,正如您所见,这使用了半偶数舍入。也就是说,如果前一个数字是偶数,它将向下舍入。我想要的是:

0.912385 -> 0.91239
0.912300 -> 0.9123

在Java中实现这一点的最佳方法是什么?


当前回答

如果您希望结果为字符串,可以使用以下内容:

DecimalFormat#setRoundingMode():DecimalFormat df=新的DecimalFormat(“#.#####”);df.setRoundingMode(RoundingMode.HALF_UP);字符串str1=df.format(0.912385));//0.91239BigDecimal#setScale()字符串str2=新BigDecimal(0.912385).setScale(5,BigDecimal.ROUND_HALF_UP).toString();

这里有一个建议,如果你想要加倍,你可以使用哪些库。不过,我不建议将其用于字符串转换,因为double可能无法准确表示您想要的内容(请参见此处的示例):

Apache Commons数学中的精度双舍入=精度舍入(0.912385,5,BigDecimal.round_HALF_UP);Colt函数双舍入=函数。舍入(0.00001)。应用(0.912385)来自Weka的Utilsdoubleround=Utils.roundDouble(0.912385,5)

其他回答

当尝试舍入到小数位数的负数时,Math.round解决方案存在问题。考虑代码

long l = 10;
for(int dp = -1; dp > -10; --dp) {
    double mul = Math.pow(10,dp);
    double res = Math.round(l * mul) / mul;
    System.out.println(""+l+" rounded to "+dp+" dp = "+res);
    l *=10;
}

这是结果

10 rounded to -1 dp = 10.0
100 rounded to -2 dp = 100.0
1000 rounded to -3 dp = 1000.0
10000 rounded to -4 dp = 10000.0
100000 rounded to -5 dp = 99999.99999999999
1000000 rounded to -6 dp = 1000000.0
10000000 rounded to -7 dp = 1.0E7
100000000 rounded to -8 dp = 1.0E8
1000000000 rounded to -9 dp = 9.999999999999999E8

当1除以1.0E-5时会出现小数位数为-5的问题,这是不精确的。

可以使用

double mul = Math.pow(10,dp);
double res;
if(dp < 0 ) {
    double div = Math.pow(10,-dp);
    res = Math.round(l * mul) *div;
} else {
    res = Math.round(l * mul) / mul;
}

但这是使用BigDecimal方法的另一个原因。

其中dp=所需的小数位数,并且值是双倍的。

    double p = Math.pow(10d, dp);

    double result = Math.round(value * p)/p;

我来这里只是想得到一个关于如何舍入数字的简单答案。这是提供这一点的补充答案。

如何在Java中舍入数字

最常见的情况是使用Math.rround()。

Math.round(3.7) // 4

数字四舍五入到最接近的整数。A.5值向上舍入。如果需要不同的舍入行为,可以使用其他数学函数之一。请参阅下面的比较。

圆形的

如上所述,这四舍五入到最接近的整数。5位小数向上舍入。此方法返回int。

Math.round(3.0); // 3
Math.round(3.1); // 3
Math.round(3.5); // 4
Math.round(3.9); // 4

Math.round(-3.0); // -3
Math.round(-3.1); // -3
Math.round(-3.5); // -3 *** careful here ***
Math.round(-3.9); // -4

ceil

任何十进制值都将舍入到下一个整数。它通向天花板。此方法返回一个double。

Math.ceil(3.0); // 3.0
Math.ceil(3.1); // 4.0
Math.ceil(3.5); // 4.0
Math.ceil(3.9); // 4.0

Math.ceil(-3.0); // -3.0
Math.ceil(-3.1); // -3.0
Math.ceil(-3.5); // -3.0
Math.ceil(-3.9); // -3.0

地板

任何十进制值都向下舍入到下一个整数。此方法返回一个double。

Math.floor(3.0); // 3.0
Math.floor(3.1); // 3.0
Math.floor(3.5); // 3.0
Math.floor(3.9); // 3.0

Math.floor(-3.0); // -3.0
Math.floor(-3.1); // -4.0
Math.floor(-3.5); // -4.0
Math.floor(-3.9); // -4.0

rint

这与舍入相似,因为十进制值舍入到最接近的整数。然而,与舍入不同,.5值舍入为偶数。此方法返回一个double。

Math.rint(3.0); // 3.0
Math.rint(3.1); // 3.0
Math.rint(3.5); // 4.0 ***
Math.rint(3.9); // 4.0
Math.rint(4.5); // 4.0 ***
Math.rint(5.5); // 6.0 ***

Math.rint(-3.0); // -3.0
Math.rint(-3.1); // -3.0
Math.rint(-3.5); // -4.0 ***
Math.rint(-3.9); // -4.0
Math.rint(-4.5); // -4.0 ***
Math.rint(-5.5); // -6.0 ***

简洁的解决方案:

   public static double round(double value, int precision) {
      int scale = (int) Math.pow(10, precision);
      return (double) (Math.round(value * scale) / scale);
  }

另请参见,https://stackoverflow.com/a/22186845/212950感谢jpdymond提供此服务。

编辑:添加圆括号。将整个结果强制加倍,而不仅仅是第一个参数!

使用setRoundingMode,显式设置Rounding模式以处理半偶数轮的问题,然后使用所需输出的格式模式。

例子:

DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.CEILING);
for (Number n : Arrays.asList(12, 123.12345, 0.23, 0.1, 2341234.212431324)) {
    Double d = n.doubleValue();
    System.out.println(df.format(d));
}

给出输出:

12
123.1235
0.23
0.1
2341234.2125

编辑:最初的答案没有提到双精度值的准确性。如果你不太在乎它是向上还是向下,那就好了。但如果您想要精确舍入,则需要考虑值的预期精度。浮点值在内部具有二进制表示。这意味着像2.7735这样的值实际上在内部没有精确的值。它可以稍大或稍小。如果内部值稍小,则不会舍入到2.7740。要纠正这种情况,您需要了解正在处理的值的准确性,并在舍入之前添加或减去该值。例如,当您知道您的值精确到6位数时,若要向上舍入中间值,请将该精度添加到值中:

Double d = n.doubleValue() + 1e-6;

要向下舍入,请减去精度。