给定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.5133
被0.0001
四舍五入。
所以问题是:如何在不诉诸暴力或字符串手术的情况下编写formatInsignificantDigits()
?我会用一点蛮力来回答我自己的问题,然后我们可以看看其他人会想出什么。
不确定这在清洁/蛮力连续体中的位置,但您也可以使用BigDecimal
和MathContext
来管理精度:
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)));
}
回答问题的数学函数"我的十进制数字有多重要"是CCD_ 9。因此,我们将分数转换为负对数,并将其转换为正数,指示我们需要填充多少个零。然后我们加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
丢失了尾部零。在某些情况下,这可能是不可接受的。。。