Java中的高效strtod?

NPE*_*NPE 5 java memory string floating-point performance

所以我有这个Java程序,我用它来咀嚼几兆兆字节的数据.性能是一个问题.

我已经分析了应用程序,并且所有内存分配的大部分以及大部分CPU时间来自执行一个简单的操作:

我有一个ASCII字符数组.我知道从offset i到offset 的字符j代表一个浮点数.我需要将该浮点数提取到一个double.

天真就是Double.parseDouble(new String(buf, i, j - i))这样.但是,这是花费大量时间和大量内存分配的地方,可能是因为:

  • new String()创建一个新对象,创建一个内部char[]数组并将字符复制到数组中;
  • Double.parseDouble() 创建一个FloatingDecimal对象,并创建一个char[]数组,同时将字符复制到其中.

所有这些分配和所有这些复制都不是必需的.我可以避开它们吗?

我真正喜欢的是一个类似于strtod函数的函数,它会接受char[](或byte[])以及开始/结束偏移,并返回一个double.

有什么建议?我应该推出自己的吗?我应该写一个JNI包装器strtod吗?我应该使用一些已经存在的Java库吗?

Thi*_*ilo 5

我想看看源java.lang.Double,复制出来,做的代码parseDouble,以我自己的助手,并修改它的工作就char[]offsetlength直接.


Pet*_*rey 5

我过去所做的是为ByteBuffer编写一个解析器(以避免字节到字符编码转换)加倍,反之亦然.如果你可以避免创建任何对象,它可以更快.此方法适用于内存映射文件,从而避免了一些复制成本.

核心代码如下所示.它不处理指数,但你可以添加它.

@Override
public double read() throws BufferUnderflowException {
  long value = 0;
  int exp = 0;
  boolean negative = false;
  int decimalPlaces = Integer.MIN_VALUE;
  while (true) {
    byte ch = buffer.get();
    if (ch >= '0' && ch <= '9') {
      while (value >= MAX_VALUE_DIVIDE_10) {
        value >>>= 1;
        exp++;
      }
      value = value * 10 + (ch - '0');
      decimalPlaces++;
    } else if (ch == '-') {
      negative = true;
    } else if (ch == '.') {
      decimalPlaces = 0;
    } else {
      break;
    }
  }

  return asDouble(value, exp, negative, decimalPlaces);
}
Run Code Online (Sandbox Code Playgroud)

完整的代码

一旦它获得任何不期望的字节,它就会停止,例如a ,\n