具有给定精度的快速双字符串转换

我需要将double转换为具有给定精度的字符串。 String.format("%.3f", value) (或DecimalFormat)完成了这项工作,但基准测试表明,与不是非常快的Double.toString转换相比,它速度很慢(在我的机器上转换100万个数字大约需要1-3秒) )。

有没有更好的方法呢?

更新:基准测试结果

从0到1000000的随机数,结果是每毫秒的运算(Java 1.7.0_45)

 Benchmark Mean Mean error Units String_format 747.394 13.197 ops/ms BigDecimal_toPlainString 1349.552 31.144 ops/ms DecimalFormat_format 1890.917 28.886 ops/ms Double_toString 3341.941 85.453 ops/ms DoubleFormatUtil_formatDouble 7760.968 87.630 ops/ms SO_User_format 14269.388 168.206 ops/ms 

更新:

Java 10,+ ryu

  Mode Cnt Score Error Units String_format thrpt 20 998.741 ± 52.704 ops/ms BigDecimal_toPlainString thrpt 20 2079.965 ± 101.398 ops/ms DecimalFormat_format thrpt 20 2040.792 ± 48.378 ops/ms Double_toString thrpt 20 3575.301 ± 112.548 ops/ms DoubleFormatUtil_formatDouble thrpt 20 7206.281 ± 307.348 ops/ms ruy_doubleToString thrpt 20 9626.312 ± 285.778 ops/ms SO_User_format thrpt 20 17143.901 ± 1307.685 ops/ms 

免责声明:如果速度是绝对要求,我只建议你使用它。

在我的机器上,以下内容可以在大约130毫秒内完成100万次转换:

  private static final int POW10[] = {1, 10, 100, 1000, 10000, 100000, 1000000}; public static String format(double val, int precision) { StringBuilder sb = new StringBuilder(); if (val < 0) { sb.append('-'); val = -val; } int exp = POW10[precision]; long lval = (long)(val * exp + 0.5); sb.append(lval / exp).append('.'); long fval = lval % exp; for (int p = precision - 1; p > 0 && fval < POW10[p]; p--) { sb.append('0'); } sb.append(fval); return sb.toString(); } 

所呈现的代码有几个缺点:它只能处理有限范围的doubles ,并且它不处理NaN。 前者可以通过扩展POW10arrays来解决(但只能部分解决)。 后者可以在代码中明确处理。

如果你需要速度和精度,我在xmlgraphics-commons开发了一个快速的DoubleFormatUtil类: http ://xmlgraphics.apache.org/commons/changes.html#version_1.5rc1

你可以在那里看到代码: http : //svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/util/DoubleFormatUtil.java?view=markup

它比DecimalFormat / BigDecimal快,和Double.toString一样快,它是精确的,它经过了很好的测试。 它是在Apache License 2.0下许可的,因此您可以根据需要使用它。

据我所知,最快最完整的实施是Jack Shirazi:

http://archive.oreilly.com/pub/a/onjava/2000/12/15/formatting_doubles.html

代码: http : //archive.oreilly.com/onjava/2000/12/15/graphics/DoubleToString.java

它提供格式化(小数位数)和未格式化的doubleToString转换。 我的观察是,多年来,未格式化转换的JDK性能得到了显着提升,所以这里的收益不再那么大了。

对于格式化转换,它仍然是。

对于基准测试员来说:使用哪种双打通常会产生很大的差异,例如,双倍非常接近0。

我没有对此进行基准测试,但是如何使用BigDecimal ?

 BigDecimal bd = new BigDecimal(value).setScale(3, RoundingMode.HALF_UP); return bd.toString();