5

我正在开发一个低延迟系统,需要一种解决方案来将双精度数转换为字节数组,但对十进制数具有精度。我需要考虑在解决方案中创建的对象应该更少。另外,我的价值是双倍的。

我目前的实现有点像

int offset = 0;
double d = 1211.11;
long integerPart = (long) d;
byte[] b = new byte[16];

offset += addToByteArray(integerPart, b, offset); 
//implementation to add each digit to byte array, returns new offset

int lengthDecimal = 16 - offset;
if(lengthDecimal > 0)
b[offset++] = '.';
long tmp = 1;

for(int i=0; i<lengthDecimal; i++){
 tmp = tmp * 10;
 int digit = (int)(((long) (d * tmp)) % 10);
 b[offset++] = (byte) ('0' + digit);
}

然后操纵字节数组以修剪后面的零和“。” 如果需要。

问题是如果我检查字节数组,我找不到确切的数字。因为,我使用的是双精度,所以在工作时会丢失小数点的精度。

我已经搜索并发现到处都可以使用 BigDecimal。BigDecimal 的使用似乎可以正常工作,但我担心这部分代码经常受到影响而创建的对象的性能和数量。

我也尝试过像这样使用 String

String doubleNumber = Double.toString(d);
long fractionalPart = 0;

offset += addToByteArray(integerPart, b, offset); 
if(doubleNumber.substring(doubleNumber.indexOf(".")).length() > 0) {
  fractionalPart = Long.valueOf(doubleNumber.substring(doubleNumber.indexOf(".") + 1));
  b[offset++] = '.';
  offset += addToByteArray(fractionalPart, b, offset);
}

请建议我为此目的的最佳方法。

4

3 回答 3

10
byte[] bytes = new byte[8];
java.nio.ByteBuffer.wrap(bytes).putDouble(yourDouble);
于 2012-12-28T00:03:19.243 回答
4

如果您真的想要低延迟,那么重要的是避免堆内存分配(这会导致 GC 在稍后的某个未指定的时间点暂停)。

所以我假设:

  • 您已经提前分配了字节数组
  • 你想在你的字节数组中放一个双精度而不做任何中间分配

诀窍是使用doubleToLongBits

long v = Double.doubleToLongBits(myDouble);

然后将 写入long字节数组中的正确位置(大概使用 8 个连续字节)。您不妨以蛮力方式执行此操作:

data[pos+7] = (byte)(v);
data[pos+6] = (byte)(v>>>8);
data[pos+5] = (byte)(v>>>16);
data[pos+4] = (byte)(v>>>24);
data[pos+3] = (byte)(v>>>32);
data[pos+2] = (byte)(v>>>40);
data[pos+1] = (byte)(v>>>48);
data[pos]   = (byte)(v>>>56);

请注意,我们在每一点都使用原语,因此在整个过程中没有内存分配。

于 2012-12-28T00:22:13.337 回答
-2

如果您想要将双重格式设置为 ASCII(字符)字符串,那么 String.format 可能是让您控制格式的最简单方法:

String result = String.formatter("%5.3f", theDoubleValue);
于 2012-12-28T00:28:15.537 回答