【问题标题】:Check partially known integer lies within a range检查部分已知整数是否在一个范围内
【发布时间】: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
  • 难道你不能用0x000xff 填充未知字节,并使用这两个可能的数字作为它可能变成的数字的最小值/最大值吗?只需检查这两个数字都在您的范围内即可。
  • 我想我需要结合使用这两个答案。 @OldCurmudgeon,我想知道未知数字是否可能(不确定)是否在该范围内。未知数的最小和最大可能值可能都位于范围之外,但它仍然可能具有位于范围内的值,在这种情况下,我希望我的方法返回 true。我将按照您的建议使用最小值和最大值来确定是否存在其他建议的范围交集。谢谢你们。
  • 现在要解决的问题是处理整数环绕和处理java中的无符号值...
  • @PaddyD 带有环绕,这些间隔被称为“顺时针间隔”,您仍然可以将它们相交。这只是有点棘手。我会找到它并回复你。

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


【解决方案1】:

假设你有一个顺时针区间 (x, y) 和一个正常区间 (low, high)(每个都包括它们的端点),确定它们是否相交可以这样做(未测试):

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;
}

若要作为无符号整数进行比较,您可以使用 longs(与 x &amp; 0xffffffffL 叠加以抵消符号扩展)或 Integer.compareUnsigned(在较新版本的 Java 中),或者,如果您愿意,您可以添加/减去/xor 两个操作数与Integer.MIN_VALUE

【讨论】:

  • 这看起来像我所追求的。 O(1) 时间复杂度。谢谢。
【解决方案2】:

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

大概整数上的符号位始终为零(如果不是,只需将负数强制转换为零,因为您的测试值不能为负数)。但是因为这只是一位,除非您将所有 32 位都指定为 n,否则这无关紧要(在这种特殊情况下问题不大)。

【讨论】:

    猜你喜欢
    • 2018-10-21
    • 2011-06-29
    • 2011-03-31
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多