如何使用 DecimalFormat() 只输出有效的小数位

how to use DecimalFormat() to only output significant fractional digits

给定 0.01835132889570552,数字 1835 很重要(可能需要四舍五入),数字 132889570552 不重要,所以我们不想把它们放在一起进入我们用户的输入系统。

小数点左边的数字有效,小数点右边的数字最少为4位。

我们需要通过这个测试:

assertEquals("1,835.1329", formatInsignificantDigits(1835.13288957055));
assertEquals("183.5133", formatInsignificantDigits(183.513288957055));
assertEquals("18.3513", formatInsignificantDigits(18.3513288957055));
assertEquals("1.8351", formatInsignificantDigits(1.83513288957055));
assertEquals("0.1835", formatInsignificantDigits(0.183513288957055));
assertEquals("0.01835", formatInsignificantDigits(0.0183513288957055));
assertEquals("0.001835", formatInsignificantDigits(0.00183513288957055));
assertEquals("0.0001835", formatInsignificantDigits(0.000183513288957055));

请注意 183.51330.0001 四舍五入。

所以问题是:如何写formatInsignificantDigits()而不诉诸蛮力或字符串手术?我会用一点蛮力回答我自己的问题,然后我们看看其他人想出了什么。

回答“我的小数位数有多重要?”这个问题的数学函数是 Math.log10()。因此,我们将分数转换为负对数,并将它们转换为正数,表示我们需要填充多少个零。然后我们加 4 得到所有数字,我们设置精度:

public static @NonNull String formatInsignificantDigits(double input) {
    DecimalFormat df = new DecimalFormat();
    //noinspection NumericCastThatLosesPrecision
    int digits = 4 + (int) -Math.log10(input);
    df.setMaximumFractionDigits(Math.max(digits, 4));
    return df.format(input);
}

有没有人有更简洁的方法来做到这一点?还是我们忽略的DecimalFormat的函数?


结果这个算法将 -0.03997394115 转换为 "0.04",因为向左级联向上舍入,然后 DecimalFormat 丢失了尾随零。在某些情况下这可能是不可接受的...

不确定这在干净/brute-force 连续体中的位置,但您也可以使用 BigDecimalMathContext 来管理精度:

    public static String formatInsignificantDigits(double value) {
        DecimalFormat format = DecimalFormat.getInstance();
        format.setMaximumFractionDigits(Integer.MAX_VALUE);
        BigDecimal bigDecimal = new BigDecimal(value);
        int wholeDigits = Math.max(bigDecimal.precision() - bigDecimal.scale(), 0);
        return format.format(bigDecimal.round(new MathContext(wholeDigits + 4)));
    }