我想要的是一种将双精度转换为字符串的方法,该字符串使用半向上舍入方法进行舍入-即,如果要舍入的小数为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将double转换为String,这非常简单:

DecimalFormat formatter = new DecimalFormat("0.0##");
formatter.setRoundingMode(RoundingMode.HALF_UP);

double num = 1.234567;
return formatter.format(num);

根据您需要的行为,有几个RoundingMode枚举值可供选择。

其他回答

@米尔豪斯:舍入的十进制格式非常好:

您也可以使用DecimalFormat df=新的DecimalFormat(“#.000000”);df.格式(0.912385);以确保后面有0。

我想补充一点,这种方法非常善于提供数字、舍入机制-不仅是视觉上的,也是处理时的。

假设:您必须在GUI中实现舍入机制程序只需更改结果输出的精度更改插入符号格式(即在括号内)。以便:

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

将作为输出返回:0.912385

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

将作为输出返回:0.91239

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

将返回为输出:0.9124

[EDIT:如果插入符号格式是这样的(“#0.#############”)为参数起见,输入小数,例如3.1415926,DecimalFormat不产生任何垃圾(例如尾随零),并将返回:3.1415926…如果你有这种倾向。当然,这有点冗长对于一些开发人员来说-但是,嘿,它的内存占用量很低在处理过程中,并且非常容易实现。]

因此本质上,DecimalFormat的优点在于它同时处理字符串外观-以及舍入精度设置的级别。埃尔戈:你以一个代码实现的价格获得两个好处

假设你有

double d = 9232.129394d;

可以使用BigDecimal

BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN);
d = bd.doubleValue();

或不带BigDecimal

d = Math.round(d*100)/100.0d;

两种解决方案d==9232.13

简洁的解决方案:

   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提供此服务。

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

我同意使用DecimalFormat或BigDecimal的答案。

请先阅读下面的更新!

但是,如果您确实希望舍入双值并获得双值结果,则可以使用上述org.apache.commons.math3.util.Precision.round(..)。该实现使用BigDecimal,速度慢,并且会产生垃圾。

decimal4j库中的DoubleRounder实用程序提供了一种类似但快速且无垃圾的方法:

 double a = DoubleRounder.round(2.0/3.0, 3);
 double b = DoubleRounder.round(2.0/3.0, 3, RoundingMode.DOWN);
 double c = DoubleRounder.round(1000.0d, 17);
 double d = DoubleRounder.round(90080070060.1d, 9);
 System.out.println(a);
 System.out.println(b);
 System.out.println(c);
 System.out.println(d);

将输出

 0.667
 0.666
 1000.0
 9.00800700601E10

看见https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility

披露:我参与了decimal4j项目。

更新:正如@iaforek指出的那样,DoubleRounder有时会返回违反直觉的结果。原因是它执行数学上正确的舍入。例如,DoubleRounder.round(256.025d,2)将向下舍入到256.02,因为表示为256.025d的双精度值略小于有理值256.025,因此将向下舍入。

笔记:

这种行为与BigDecimal(double)构造函数非常相似(但与使用字符串构造函数的valueOf(double)不同)。这个问题可以先用双倍的舍入步骤以更高的精度来解决,但它很复杂,我不打算在这里讨论细节

出于这些原因以及本文中提到的所有内容,我不建议使用DoubleRounder。

试试看:org.apache.commons.math3.util.Precision.round(双x,int scale)

参见:http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html

Apache Commons数学图书馆主页:http://commons.apache.org/proper/commons-math/index.html

该方法的内部实现是:

public static double round(double x, int scale) {
    return round(x, scale, BigDecimal.ROUND_HALF_UP);
}

public static double round(double x, int scale, int roundingMethod) {
    try {
        return (new BigDecimal
               (Double.toString(x))
               .setScale(scale, roundingMethod))
               .doubleValue();
    } catch (NumberFormatException ex) {
        if (Double.isInfinite(x)) {
            return x;
        } else {
            return Double.NaN;
        }
    }
}