我想要的是一种将双精度转换为字符串的方法,该字符串使用半向上舍入方法进行舍入-即,如果要舍入的小数为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中实现这一点的最佳方法是什么?


当前回答

当尝试舍入到小数位数的负数时,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方法的另一个原因。

其他回答

为此,我们可以使用此格式化程序:

 DecimalFormat df = new DecimalFormat("#.00");
 String resultado = df.format(valor)

or:

DecimalFormat df = new DecimalFormat("0.00"); :

使用此方法始终获得两个小数:

   private static String getTwoDecimals(double value){
      DecimalFormat df = new DecimalFormat("0.00"); 
      return df.format(value);
    }

定义此值:

91.32
5.22
11.5
1.2
2.6

使用该方法,我们可以得到以下结果:

91.32
5.22
11.50
1.20
2.60

在线演示。

非常简单的方法

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

    DecimalFormat deciFormat = new DecimalFormat();
    deciFormat.setMaximumFractionDigits(places);
    String newValue = deciFormat.format(value);

    return Double.parseDouble(newValue);

}

double a = round(12.36545, 2);
public static double formatDecimal(double amount) {
    BigDecimal amt = new BigDecimal(amount);
    amt = amt.divide(new BigDecimal(1), 2, BigDecimal.ROUND_HALF_EVEN);
    return amt.doubleValue();
}

使用Junit进行测试

@RunWith(Parameterized.class)
public class DecimalValueParameterizedTest {

  @Parameterized.Parameter
  public double amount;

  @Parameterized.Parameter(1)
  public double expectedValue;

@Parameterized.Parameters
public static List<Object[]> dataSets() {
    return Arrays.asList(new Object[][]{
            {1000.0, 1000.0},
            {1000, 1000.0},
            {1000.00000, 1000.0},
            {1000.01, 1000.01},
            {1000.1, 1000.10},
            {1000.001, 1000.0},
            {1000.005, 1000.0},
            {1000.007, 1000.01},
            {1000.999, 1001.0},
            {1000.111, 1000.11}
    });
}

@Test
public void testDecimalFormat() {
    Assert.assertEquals(expectedValue, formatDecimal(amount), 0.00);
}

试试看: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;
        }
    }
}

DecimalFormat是最好的输出方式,但我不喜欢它。我总是这样做,因为它返回双倍值。所以我可以使用它而不仅仅是输出。

Math.round(selfEvaluate*100000d.0)/100000d.0;

OR

Math.round(selfEvaluate*100000d.0)*0.00000d1;

如果需要大的小数位数值,可以改用BigDecimal。无论如何,0很重要。没有它,0.33333d5的舍入返回0.33333,只允许9位数字。没有.0的第二个函数有问题,返回0.3000000000000004。