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.
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.
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
.
So the question is: How to write formatInsignificantDigits()
without resorting to brute force or string surgery? 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:
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)));
}