13

我需要以给定的精度将双精度转换为字符串。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,+

                                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
4

4 回答 4

19

免责声明:我只建议您在速度是绝对要求的情况下使用它。

在我的机器上,以下可以在大约 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。前者可以通过扩展POW10数组来解决(但只能部分解决)。后者可以在代码中显式处理。

于 2012-05-11T15:15:06.673 回答
8

如果您需要速度和精度,我在 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 下获得许可,因此您可以随意使用它。

于 2012-10-02T09:42:52.967 回答
2

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

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

代码:原始实现不再在线提供(http://archive.oreilly.com/onjava/2000/12/15/graphics/DoubleToString.java)。可以在这里找到一个实现:https ://raw.githubusercontent.com/openxal/openxal/57392be263b98565738d1962ba3b53e5ca60e64e/core/src/xal/tools/text/DoubleToString.java

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

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

对于基准测试人员:使用哪种类型的双精度通常会产生很大的不同,例如非常接近 0 的双精度。

于 2017-05-04T06:53:06.470 回答
-2

我没有对此进行基准测试,但是使用BigDecimal怎么样?

BigDecimal bd = new BigDecimal(value).setScale(3, RoundingMode.HALF_UP);
return bd.toString();
于 2012-05-11T14:57:43.520 回答