检查数字是否在范围内时,使用unsigned int进行翻转问题

时间:2013-07-11 04:22:38

标签: c++ c

我正在尝试检查收到的消息号是否在给定范围内。每当消息号增加时。如果我期待数字10,我接受任何号码为10+的消息。所以序列号为10到15.我使用的是unsigned int。因此,当预期数量为65532时,我可以接受65532 + 10(所以min = 65532和max = 5)。如何检查我收到的号码是否在此范围内?

3 个答案:

答案 0 :(得分:6)

简单地减去

unsigned message_number, expected_number;
unsigned range = 5;  // or 10,  OP’s post varies as to the desired range.
if ((message_number - expected_number) <= range) {
  ;  // accept;
}

很好地定义了无符号算术的环绕。

[编辑]

如果message_numberunsigned位于同一位置,则上述解决方案效果很好。以下解决方案没有做出这样的假设,也没有假设message_number在unsigned short处回绕。

unsigned maxsequenceplus1_number = 65536LU;
if (((message_number - expected_number)%maxsequenceplus1_number) <= range) {
  ;  // accept;
}

const unsigned maxsequence_number = 65535U; // some power of 2 minus 1
if (((message_number - expected_number)&maxsequence_number) <= range) {
  ;  // accept;
}

答案 1 :(得分:1)

如果使用unsigned,你会得到GF(2 k )算术的某个值k [编辑:加法和减法,完整的有限域是更多的工作;也许我应该采用其他一些简写术语?]。通常,unsigned short k为16,unsigned int为32,而unsigned long long为64,但无论如何至少为16(因为UINT_MAX为至少65535)。

在这种finite field arithmetic中,您可以简单地减去两个数字,并将结果与​​您的限制进行比较。也就是说,如果“允许值”的范围是从x到x + 5并且您收到的实际值是y,那么:

unsigned int x, y, diff;
...
diff = y - x;
if (diff <= 5) {
    the value is in range
} else {
    the value is out of range
}

只要“范围内”窗口不超过2 k-1 ,并且由于k> = 16,这意味着您的窗口空间至少为32767,这样就可以正常工作。

如果您希望使用unsigned short C中的一条皱纹是unsigned short在通常情况下扩展为(已签名,普通)int而非unsigned int INT_MAX >= USHRT_MAX。所以你必须强制转换为unsigned int进行减法:

unsigned short x, y, diff;
....
diff = (unsigned int)y - (unsigned int)x;

代码的其余部分保持不变(请注意,将unsigned int分配回unsigned short的定义很明确,因为它减少了mod 2 k 的值。

答案 2 :(得分:1)

要使用16位整数(即范围0到65535)获得正确的结果,可以使用unsigned short来存储值。然后翻转就可以了。

但你需要小心。仅仅因为您将所有变量声明为unsigned short,2 unsigned shorts之间的差异实际上可以自动转换为int,这将破坏您的代码。

例如,

void test(unsigned short incoming, unsigned short min, unsigned short range)
{
 if ((incoming - min) >= 0 && (incoming - min) <  range)
   printf("in range");       
 else
   printf("out of range");
}

如果您输入incoming=5min=0xFFFF以及range=5,此将失败。即使不在范围内,它也会打印在“范围内”。

要解决此问题,您需要执行

void test(unsigned short incoming, unsigned short min, unsigned short range)
{
 if ((unsigned short)(incoming - min) >= 0 &&
     (unsigned short)(incoming - min) <  range)
   printf("in range");       
 else
   printf("out of range");
}

这是c语言中有争议的一点。该规范允许在大于给定数据大小(短)的寄存器中执行减法。大多数计算机都有32位或64位寄存器,因此减法由int个有符号的寄存器执行。因此0x00000005 - 0x0000FFFF = 0xFFFF0006,这是负数(-65530)而不仅仅是6.您需要重新回到原始数据类型(无符号短路)以取回6。

有关整数提升的讨论,请参阅In a C expression where unsigned int and signed int are present, which type will be promoted to what type?

你也可以这样做,这可能是最好的答案。我取出了delta >= 0的比较,因为无符号整数总是如此。并且还切换到使用 stdint.h

#include <stdint.h>

void test(uint16_t incoming, uint16_t  min, uint16_t  range)
{
 uint16_t  delta = incoming - min;
 if (delta <  range)
   printf("in range");       
 else
   printf("out of range");
}