首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >更快的替代DecimalFormat.format()?

更快的替代DecimalFormat.format()?
EN

Stack Overflow用户
提问于 2011-12-18 18:08:13
回答 4查看 15K关注 0票数 23

为了提高它的性能,我一直在用VisualVM采样器分析我的一个应用程序,使用20 my的最小采样周期。根据分析器,主线程在DecimalFormat.format()方法中花费了几乎四分之一的CPU时间。

我使用DecimalFormat.format()0.000000模式“将”double数字“转换”为一个精确有6个小数位数的字符串表示。我知道这种方法比较昂贵,被称为很多次,但我仍然对这些结果感到有些惊讶。

  1. 这样的取样剖面仪的结果在多大程度上是准确的?我应该怎么做才能更好地验证它们--而不诉诸于仪器剖析器呢?
  2. 对于我的用例,有比DecimalFormat更快的替代方案吗?推出我自己的NumberFormat子类有意义吗?

更新:

我创建了一个微基准来比较以下三种方法的性能:

  • DecimalFormat.format():单个DecimalFormat对象多次重用。
  • String.format():多个独立电话。在内部,这种方法归结为 公共静态字符串格式(字符串格式,对象.{返回新格式化程序().format(格式,args).toString();} 因此,我预计它的性能非常类似于Formatter.format()
  • Formatter.format():单个Formatter对象多次重用。 这个方法有点尴尬--使用默认构造函数创建的Formatter对象将format()方法创建的所有字符串附加到内部StringBuilder对象,该对象无法正确访问,因此无法清除。因此,对format()的多次调用将创建所有结果字符串的连接。 为了解决这个问题,我提供了自己的StringBuilder实例,在使用setLength(0)调用之前清除了这些实例。

有趣的结果:

  • DecimalFormat.format()为基线,为1.4us /次。
  • String.format()在每次通话2.7us时降低了2倍。
  • 在每次通话2.5us时,Formatter.format()的速度也是原来的两倍。

现在看来,DecimalFormat.format()仍然是这些替代方案中最快的。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-12-18 22:01:11

如果你知道你想要什么,你可以写你自己的例行公事。

代码语言:javascript
复制
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);
}

版画

代码语言:javascript
复制
Took 128 ns per append double

如果您想要更高的性能,您可以直接写入ByteBuffer (假设您想要在某个地方写入数据),因此您生成的数据确实需要被复制或编码。(假设这是可以的)

注意:这仅限于小于9万亿(Long.MAX_VALUE/1e6)的正/负值,如果这可能是问题,您可以添加特殊处理。

票数 11
EN

Stack Overflow用户

发布于 2011-12-18 18:13:14

也许你的程序并没有做很多密集的工作,所以这似乎是做得最多的一些数字。

我的观点是,您的结果仍然相对于您的应用程序。

在每个DecimalFormatter.format()周围设置一个计时器,看看您使用了多少millis来获得更清晰的图片。

票数 2
EN

Stack Overflow用户

发布于 2011-12-18 18:22:28

另一种选择是使用字符串格式化程序,尝试查看它的性能是否更好:

代码语言:javascript
复制
String.format("%.6f", 1.23456789)

或者更好的是,创建单个格式化程序并重用它--只要不存在多线程问题,因为格式化程序对于多线程访问不一定安全:

代码语言:javascript
复制
Formatter formatter = new Formatter();
// presumably, the formatter would be called multiple times
System.out.println(formatter.format("%.6f", 1.23456789));
formatter.close();
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8553672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档