A faster alternative to DecimalFormat.format()?

You can write your own routine given you know exactly what you want.

public static void appendTo6(StringBuilder builder, double d) {
    if (d < 0) {
        builder.append('-');
        d = -d;
    }
    if (d * 1e6 + 0.5 > Long.MAX_VALUE) {
        // TODO write a fall back.
        throw new IllegalArgumentException("number too large");
    }
    long scaled = (long) (d * 1e6 + 0.5);
    long factor = 1000000;
    int scale = 7;
    long scaled2 = scaled / 10;
    while (factor <= scaled2) {
        factor *= 10;
        scale++;
    }
    while (scale > 0) {
        if (scale == 6)
            builder.append('.');
        long c = scaled / factor % 10;
        factor /= 10;
        builder.append((char) ('0' + c));
        scale--;
    }
}

@Test
public void testCases() {
    for (String s : "-0.000001,0.000009,-0.000010,0.100000,1.100000,10.100000".split(",")) {
        double d = Double.parseDouble(s);
        StringBuilder sb = new StringBuilder();
        appendTo6(sb, d);
        assertEquals(s, sb.toString());
    }
}

public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();
    long start = System.nanoTime();
    final int runs = 20000000;
    for (int i = 0; i < runs; i++) {
        appendTo6(sb, i * 1e-6);
        sb.setLength(0);
    }
    long time = System.nanoTime() - start;
    System.out.printf("Took %,d ns per append double%n", time / runs);
}

prints

Took 128 ns per append double

If you want even more performance you can write to a direct ByteBuffer (assuming you want to write the data somewhere) so the data you produce does need to be copied or encoded. (Assuming that is ok)

NOTE: this is limited to positive/negative values of less than 9 trillion (Long.MAX_VALUE/1e6) You can add special handling if this might be an issue.


Maybe your program doesn't do much intensive work and so this appears to do the most - crunching some numbers.

My point is that your results are still relative to your app.

Put a timer around each DecimalFormatter.format() and see how many millis you are using to get a clearer picture.


An alternative would be to use the string Formatter, give it a try to see if it performs better:

String.format("%.6f", 1.23456789)

Or even better, create a single formatter and reuse it - as long as there are no multithreading issues, since formatters are not necessarily safe for multithreaded access:

Formatter formatter = new Formatter();
// presumably, the formatter would be called multiple times
System.out.println(formatter.format("%.6f", 1.23456789));
formatter.close();