简体   繁体   English

如何将 DecimalFormat() 用于仅 output 有效小数位

[英]how to use DecimalFormat() to only output significant fractional digits

Given 0.01835132889570552 , the digits 1835 are significant (and might need to round up), and the digits 132889570552 are insignificant, so we don't want to put them into our user's input systems.给定0.01835132889570552 ,数字1835很重要(可能需要四舍五入),而数字132889570552不重要,因此我们不想将它们放入用户的输入系统。

Any digits to the left of the decimal place are significant, and the minimum number of numerals to the right of the decimal place is 4.小数点左边的数字都是有效的,小数点右边的数字最少是4位。

We need to pass this test:我们需要通过这个测试:

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));

Note that 183.5133 rounded up by 0.0001 .请注意, 183.51330.0001四舍五入。

So the question is: How to write formatInsignificantDigits() without resorting to brute force or string surgery?所以问题是:如何在不诉诸蛮力或字符串手术的情况下编写formatInsignificantDigits() I will answer my own question with a little brute force, and then we can see what others come up with.我会用一点蛮力回答我自己的问题,然后我们可以看看其他人的想法。

Not sure where this fits on the clean / brute-force continuum, but you could also make use of BigDecimal and MathContext to manage precision:不确定这在干净/蛮力连续统中的位置,但您也可以使用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)));
    }

The math function to answer the question "How significant are my decimal digits?"数学 function 用于回答“我的十进制数字有多重要?”这个问题is Math.log10() .Math.log10() So we convert our fractions into negative logarithms, and turn them into a positive number indicating how many zeros we need to pad.因此,我们将分数转换为负对数,并将它们转换为正数,表示我们需要填充多少个零。 Then we add 4 to get all the digits, and we set that amount of precision:然后我们加 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);
}

Does anyone have a cleaner way to do this?有没有人有更清洁的方法来做到这一点? Or a function of DecimalFormat that we overlooked?还是我们忽略的DecimalFormat的 function?


And it turns out this algorithm converts -0.03997394115 to "0.04" , because rounding up cascaded to the left, and then DecimalFormat lost the trailing zeros.事实证明,该算法将-0.03997394115转换为"0.04" ,因为向上舍入级联到左侧,然后DecimalFormat丢失了尾随零。 That might not be acceptable in some circumstances...在某些情况下这可能是不可接受的......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM