检查部分已知的整数是否在一个范围内

时间:2014-08-14 10:42:55

标签: java performance int bit-manipulation low-level

我有一个特殊的问题,我正在寻找一个有效的解决方案。我有一个字节数组,其中包含无符号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;
}

2 个答案:

答案 0 :(得分:1)

将无符号字节转换为整数。右移32-n(所以你有意义的字节是最小字节)。右移你的最小/最大整数相同的数量。如果您的移位测试值等于移位整数,则可能在该范围内。如果在它们之间,它肯定在范围内。

假设整数上的符号位始终为零(如果不是,则强制将负数转换为零,因为您的测试值不能为负)。但是因为那只有一位,除非你把全部32位作为n,否则这不重要(在这种特殊情况下它不是什么大问题)。

答案 1 :(得分:1)

假设您有一个顺时针间隔(x,y)和一个正常间隔(低,高)(每个包括它们的端点),确定它们是否相交可以完成(未测试):

if (x <= y) {
    // (x, y) is a normal interval, use normal interval intersect
    return low <= y && high >= x;
}
else {
    // (x, y) wraps
    return low <= y || high >= x;
}

要比较为无符号整数,您可以使用long s(使用x & 0xffffffffL进行反对来抵消符号扩展)或Integer.compareUnsigned(在较新版本的Java中),或者如果您使用您更喜欢使用Integer.MIN_VALUE添加/减去/ xor两个操作数。