比较存储在字节数组中的双精度的最有效方法是什么?

时间:2011-10-03 23:48:38

标签: java

想象一下,我有两个byte []数组,b1和b2,它们的字节对应两个双精度数。 一种选择就是......

double thisValue = readDouble(b1, s1);
double thatValue = readDouble(b2, s2);
return (thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1));

使用......

/** Parse an integer from a byte array. */
public static int readInt(byte[] bytes, int start) {
  return (((bytes[start  ] & 0xff) << 24) +
          ((bytes[start+1] & 0xff) << 16) +
          ((bytes[start+2] & 0xff) <<  8) +
          ((bytes[start+3] & 0xff)));
}

/** Parse a long from a byte array. */
public static long readLong(byte[] bytes, int start) {
  return ((long)(readInt(bytes, start)) << 32) +
    (readInt(bytes, start+4) & 0xFFFFFFFFL);
}

/** Parse a double from a byte array. */
public static double readDouble(byte[] bytes, int start) {
  return Double.longBitsToDouble(readLong(bytes, start));
}

(代码取自apache hadoop source herehere)。

问题是,你有他们的字节表示,所以看起来浪费实际上必须把它们变成双重,尽管这可能是如此大大优化,可以忽略不计。我确信Hadoop的人知道他们在做什么,我只是好奇为什么直接比较这些比特不会更好/更快?或者也许编译器足够智能,可以看到这种情况并做到这一点。

由于

4 个答案:

答案 0 :(得分:1)

由于structureIEEE floating-point format,您不能简单地检查所有位是否相同:例如,-0和+0具有不同的表示,但被认为是相等的;和具有许多不同表示的NaN值永远不会等于任何东西,包括具有相同表示的其他NaN值。

虽然你自己可以自己实现这些检查,但它很快变得非常复杂,并且不值得:你需要检查的“子值”没有自己的字节,所以你仍然必须提取字节并抛出它们变成更大的值 - 然后你必须实际检查所有不同的条件。

换句话说,你最终会做上述代码所做的事情,但是你需要花费更多的代码,并且你不太可能比已经存在的代码更好。< / p>

答案 1 :(得分:0)

一个字节数组可能包含标准化double值的位模式,另一个字节数组包含相同值的非标准化表示。在这种情况下,在比较字节值失败的情况下,转换和比较为double值将会成功。

答案 2 :(得分:0)

通过逐位比较比较浮点值存在很多问题 - 例如,一个数字可能是非正规数而另一个数字不是。它们可能是“相同的”或可比的,但它们的按位表示不会。

答案 3 :(得分:0)

我想说,你将获得“最有效”答案的唯一真正方法是进行15-20分钟的实验。老实说,我不知道使用详细的hadoop方法是否比将byte []加载到ByteArrayInputStream并使用DataInputStream装饰该流更快(或更多/更不准确)。 (DataInputStream有一个.getDouble()方法)

byte[] myData = ........
ByteArrayInputStream bais = ByteArrayInputStream(myData);
DataInputStream dis = DataInputStream(bais);

double d1 = dis.getDouble();
double d2 = dis.getDouble();

告诉我们你的基准是什么!