【发布时间】:2014-08-14 10:42:54
【问题描述】:
我有一个特殊的问题,我正在寻找一个有效的解决方案。我有一个字节数组,其中包含无符号 4 字节整数的最重要的 n 个字节(首先是最重要的 sig 字节)。剩余字节(如果有)的值是未知的。我需要检查部分已知的整数值是否可以落在已知整数的某个范围(+ 或 - x)内。对被测字节数组表示的整数进行回绕也是有效的。
我有一个可行的解决方案(如下)。问题是这个解决方案执行的比较比我认为必要的要多,并且在最小 sig 字节未知的情况下,整个比较负载将被复制。我很确定它可以更有效地完成,但无法弄清楚如何。最低有效字节未知的情况是一种边缘情况,因此我可能能够忍受它,但它构成了需要低延迟的系统的一部分,所以如果有人可以帮助解决这个问题,那就太好了。
提前致谢。
static final int BYTES_IN_INT = 4;
static final int BYTE_SHIFT = 010;
// partial integer byte array length guaranteed to be 1-4 so no checking necessary
static boolean checkPartialIntegerInRange(byte[] partialIntegerBytes, int expectedValue, int range)
{
boolean inRange = false;
if(partialIntegerBytes.length == BYTES_IN_INT)
{
// normal scenario, all bytes known
inRange = Math.abs(ByteBuffer.wrap(partialIntegerBytes).getInt() - expectedValue) <= range;
}
else
{
// we don't know least significant bytes, could have any value
// need to check if partially known int could lie in the range
int partialInteger = 0;
int mask = 0;
// build partial int and mask
for (int i = 0; i < partialIntegerBytes.length; i++)
{
int shift = ((BYTES_IN_INT - 1) - i) * BYTE_SHIFT;
// shift bytes to correct position
partialInteger |= (partialIntegerBytes[i] << shift);
// build up mask to mask off expected value for comparison
mask |= (0xFF << shift);
}
// check partial int falls in range
for (int i = -(range); i <= range; i++)
{
if (partialInteger == ((expectedValue + i) & mask))
{
inRange = true;
break;
}
}
}
return inRange;
}
编辑:感谢下面的贡献者。这是我的新解决方案。欢迎评论。
static final int BYTES_IN_INT = 4;
static final int BYTE_SHIFT = 010;
static final int UBYTE_MASK = 0xFF;
static final long UINT_MASK = 0xFFFFFFFFl;
public static boolean checkPartialIntegerInRange(byte[] partialIntegerBytes, int expectedValue, int range)
{
boolean inRange;
if(partialIntegerBytes.length == BYTES_IN_INT)
{
inRange = Math.abs(ByteBuffer.wrap(partialIntegerBytes).getInt() - expectedValue) <= range;
}
else
{
int partialIntegerMin = 0;
int partialIntegerMax = 0;
for(int i=0; i < BYTES_IN_INT; i++)
{
int shift = ((BYTES_IN_INT - 1) - i) * BYTE_SHIFT;
if(i < partialIntegerBytes.length)
{
partialIntegerMin |= (((partialIntegerBytes[i] & UBYTE_MASK) << shift));
partialIntegerMax = partialIntegerMin;
}
else
{
partialIntegerMax |=(UBYTE_MASK << shift);
}
}
long partialMinUnsigned = partialIntegerMin & UINT_MASK;
long partialMaxUnsigned = partialIntegerMax & UINT_MASK;
long rangeMinUnsigned = (expectedValue - range) & UINT_MASK;
long rangeMaxUnsigned = (expectedValue + range) & UINT_MASK;
if(rangeMinUnsigned <= rangeMaxUnsigned)
{
inRange = partialMinUnsigned <= rangeMaxUnsigned && partialMaxUnsigned >= rangeMinUnsigned;
}
else
{
inRange = partialMinUnsigned <= rangeMaxUnsigned || partialMaxUnsigned >= rangeMinUnsigned;
}
}
return inRange;
}
【问题讨论】:
-
你有两个范围;您的 int 的可能值范围和“允许”范围。每个范围由两个端点定义。您所要做的就是确定whether these ranges intersect。
-
难道你不能用
0x00和0xff填充未知字节,并使用这两个可能的数字作为它可能变成的数字的最小值/最大值吗?只需检查这两个数字都在您的范围内即可。 -
我想我需要结合使用这两个答案。 @OldCurmudgeon,我想知道未知数字是否可能(不确定)是否在该范围内。未知数的最小和最大可能值可能都位于范围之外,但它仍然可能具有位于范围内的值,在这种情况下,我希望我的方法返回 true。我将按照您的建议使用最小值和最大值来确定是否存在其他建议的范围交集。谢谢你们。
-
现在要解决的问题是处理整数环绕和处理java中的无符号值...
-
@PaddyD 带有环绕,这些间隔被称为“顺时针间隔”,您仍然可以将它们相交。这只是有点棘手。我会找到它并回复你。
标签: java performance int bit-manipulation low-level