C 如何使用位运算符比较两个无符号整数?
在不使用任何算术运算符或比较运算符的情况下,如何使用逐位运算符来确定两个无符号整数中的较大者?如果您处理的是数字的十进制表示形式,您会说数字最多的一个是较大的一个 如果两个数字的位数相同怎么办?你依次比较每个数字,从最重要的开始 用十进制表示,在满足您的要求时,这将很难实现。但在二进制中,我们可以执行简单的真理测试。因此,这里可以使用这种方法C 如何使用位运算符比较两个无符号整数?,c,boolean,logic,C,Boolean,Logic,在不使用任何算术运算符或比较运算符的情况下,如何使用逐位运算符来确定两个无符号整数中的较大者?如果您处理的是数字的十进制表示形式,您会说数字最多的一个是较大的一个 如果两个数字的位数相同怎么办?你依次比较每个数字,从最重要的开始 用十进制表示,在满足您的要求时,这将很难实现。但在二进制中,我们可以执行简单的真理测试。因此,这里可以使用这种方法 +---+---+---+---+ +---+---+---+---+ | 0 | 1 | 1 | 0 | 6 | 0 | 1 | 1
+---+---+---+---+ +---+---+---+---+
| 0 | 1 | 1 | 0 | 6 | 0 | 1 | 1 | 0 | 6
+---+---+---+---+ +---+---+---+---+
→ ↑ ↑ → → ↑ ↑
+---+---+---+---+ +---+---+---+---+
| 0 | 0 | 1 | 0 | 2 | 0 | 1 | 0 | 0 | 4
+---+---+---+---+ +---+---+---+---+
因此,这适用于大小相同的无符号整数:
有一个更简单的解决方案,包括寻找两个输入数的异或。
让我们考虑两个整数4(0100)和3(0011)。我们需要生成区分两个整数的最大子比特序列,例如上面的它是0100(因为第三个比特不同),然后我们可以通过生成比特和运算简单地知道哪个更大:
0100 & 0100 = 0100 > 0
0011 & 0100 = 0
代码如下:
#include <stdio.h>
int main()
{
int a, b;
printf("Enter two numbers\n");
scanf("%d%d", &a, &b);
int diff = a ^ b;
if (diff) //true means both are not equal
{
diff = diff | (diff >> 1);
diff |= diff >> 2;
diff |= diff >> 4;
diff |= diff >> 8;
diff |= diff >> 16;
diff ^= diff >> 1;
int res = (a & diff) ? 1 : 0;
if (res)
printf("%d greater than %d", a, b);
else
printf("%d greater than %d", b, a);
}
else //both equal
{
printf("Both are equal\n");
return 0;
}
return 0;
}
#包括
int main()
{
INTA,b;
printf(“输入两个数字\n”);
scanf(“%d%d”、&a和&b);
int diff=a^b;
if(diff)//true表示两者不相等
{
diff=diff |(diff>>1);
diff |=diff>>2;
diff |=diff>>4;
diff |=diff>>8;
diff |=diff>>16;
diff^=diff>>1;
int res=(a&diff)?1:0;
如果(res)
printf(“%d大于%d”,a,b);
其他的
printf(“%d大于%d”,b,a);
}
否则,两者都相等
{
printf(“两者相等”);
返回0;
}
返回0;
}
在循环中使用XOR(异或)和SHL(左移)将完成这项工作
XOR(在C:^
中)是[在低级别H/W中]测试相等性的正常方法。这是一个基本的逻辑门
如果两个数的XOR为零,则它们相等
但是,两个数字的异或产生一个位掩码,如果两个数字中的任何一个位不同,则相应的异或位为1(否则为0)
通过对MSB进行移位和掩蔽,我们可以找到不同的最左边的位
这里有一些代码说明了这一点。它有一个诊断测试,因此您可以验证您的功能:
#include <stdio.h>
#include <stdlib.h>
typedef unsigned int u32;
// RETURNS -1=a<b, 0=a==b, +1=a>b
int
cmpxor(u32 a,u32 b)
{
u32 xor;
u32 msb;
int cmp = 0;
// get a mask for the most signifcant bit
msb = 1u << 31;
// which bits are different
xor = a ^ b;
while (xor != 0) {
// is the most significant bit different? if so, we are done
if (xor & msb) {
if (a & msb)
cmp = 1;
else
cmp = -1;
break;
}
xor <<= 1;
a <<= 1;
}
return cmp;
}
int
cmpstd(u32 a,u32 b)
{
int cmp = 0;
if (a < b)
cmp = -1;
if (a > b)
cmp = 1;
return cmp;
}
int
main(int argc,char **argv)
{
u32 a;
u32 b;
int cmpx;
int cmps;
u32 opt_L = 0;
int code = 0;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'L':
opt_L = (*cp != 0) ? atoll(cp) : 65536;
break;
}
}
if (opt_L == 0)
opt_L = 1024;
for (a = 0; a < opt_L; ++a) {
for (b = 0; b < opt_L; ++b) {
cmps = cmpstd(a,b);
cmpx = cmpxor(a,b);
if (cmps != cmpx) {
printf("a=%8.8X b=%8.8X cmps=%d cmpx=%d\n",
a,b,cmps,cmpx);
code = 1;
break;
}
}
if (code)
break;
}
if (code == 0)
printf("complete\n");
return code;
}
我增强测试套件的原因是,我觉得在cmpki
[克里希纳的原始算法]中使用带符号的int
可能会对带符号位集的数字产生问题[因为算术右移与逻辑右移的语义不同]。而且,因为最初的问题是数字是无符号的
我添加了一个无符号版本,解决了这个问题。有符号整数还是无符号整数?64位、32位、16位还是8位?你试过什么?对不起,它没有签名。提示:在C中,零是假,非零是真。这是在没有比较运算符的情况下获得分支的唯一方法。另请参见使用逐位运算比较两个无符号整数,您需要找到两个二进制表示形式不同的最高有效位。循环中的移位和遮罩。速度慢-但这就是为什么计算机以单一操作码的形式提供操作,而不需要你做这样的家庭作业。我检查了我的系统,它工作正常(Ubuntu)。谢谢你的帮助。我今天下班回家后再做数学题。至少我会有一些指导。这真的很有帮助。@Ryanv048不客气。如果有帮助的话,请投票并接受。我很好奇你使用带符号的
int
。因此,我在测试程序中添加了一个从您的算法派生的测试函数[和一个使用无符号的函数]。对于符号位不同的值,原始代码将失败。当您切换到unsigned时,它可以正常工作。因此,您可能需要将代码更改为使用unsigned int
@CraigEstey是的,您是正确的。代码不适用于符号不同的数字。但是问题--->“两个无符号整数中的较大者”@CraigEstey您不应该使用比较运算符while(xor!=0)
-->ComparisonThanks Craig为您提供帮助,我也为您的回复迟到表示歉意。它给了我一个如何做的指导。我真的很感激。我们不应该使用任何比较运算符。您已经使用了
,==
和=代码>运算符。@KrishnaKanthYenumula我只使用了xor!=0
[在中,而]。使用任何if/while/?:
都是一种比较,即使它是if(val)
——也无法回避这一点。您使用了if(diff==0)
。我没有使用
。如果您指的是cmpstd
,那么这只是单元测试套件的一部分,用于提供验证“真实”代码的参考(例如cmpxor
[和cmpki/cmpku
])。正如我提到的,XOR是一个基本逻辑门,用于硬件中测试相等/不相等。问题其实是如何使用基本逻辑。问题只需要gt
,但我们都选择了cmp
@CraigEstey谢谢你的建议。我编辑了它。我删除了=
操作符的用法。在if(res)if(diff)
-->中,不使用比较运算符。谢谢您的回复。当你说隔离最重要的,你的意思是使用移位运算符。就在右边。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef unsigned int u32;
typedef unsigned long long u64;
u32 opt_L = 0;
int opt_e; // number of errors to show per func
int opt_k; // don't stop next test if error
int opt_v; // show all values
// RETURNS -1=a<b, 0=a==b, +1=a>b
int
cmpxor(u32 a,u32 b)
{
u32 xor;
u32 msb;
int cmp = 0;
// get a mask for the most signifcant bit
msb = 1u << 31;
// which bits are different
xor = a ^ b;
while (xor != 0) {
// is the most significant bit different? if so, we are done
if (xor & msb) {
if (a & msb)
cmp = 1;
else
cmp = -1;
break;
}
xor <<= 1;
a <<= 1;
}
return cmp;
}
int
cmpstd(u32 a,u32 b)
{
int cmp = 0;
if (a < b)
cmp = -1;
if (a > b)
cmp = 1;
return cmp;
}
int
cmpki(int a, int b)
{
int diff = a ^ b;
int res;
do {
// Both are equal
if (diff == 0) {
res = 0;
break;
}
diff = diff | (diff >> 1);
diff |= diff >> 2;
diff |= diff >> 4;
diff |= diff >> 8;
diff |= diff >> 16;
diff ^= diff >> 1;
// Conditonal operator is not a relational operator
res = (a & diff) ? 1 : -1;
} while (0);
return res;
}
int
cmpku(u32 a, u32 b)
{
u32 diff = a ^ b;
int res;
do {
// Both are equal
if (diff == 0) {
res = 0;
break;
}
diff = diff | (diff >> 1);
diff |= diff >> 2;
diff |= diff >> 4;
diff |= diff >> 8;
diff |= diff >> 16;
diff ^= diff >> 1;
// Conditonal operator is not a relational operator
res = (a & diff) ? 1 : -1;
} while (0);
return res;
}
double tsczero;
double tscbeg;
double
tscget(void)
{
struct timespec ts;
double sec;
clock_gettime(CLOCK_MONOTONIC,&ts);
sec = ts.tv_nsec;
sec /= 1e9;
sec += ts.tv_sec;
if (tsczero == 0)
tsczero = sec;
sec -= tsczero;
return sec;
}
#define msgbeg(_fmt...) \
do { \
tscbeg = tscget(); \
printf("%13.9f ",tscbeg); \
printf(_fmt); \
fflush(stdout); \
} while (0)
void
msgend(void)
{
double tscend = tscget();
printf(" (ELAPSED: %.9f)\n",tscend - tscbeg);
}
typedef struct {
int (*tst_fnc)(u32,u32);
const char *tst_tag;
} tst_t;
tst_t tstlist[] = {
{ .tst_tag = "cmpxor", .tst_fnc = (void *) cmpxor },
{ .tst_tag = "cmpki", .tst_fnc = (void *) cmpki },
{ .tst_tag = "cmpku", .tst_fnc = (void *) cmpku },
{ .tst_tag = NULL }
};
int taglen;
int
dotest(tst_t *tst,u64 lo,u64 hi,u32 inc)
{
u64 a;
u64 b;
int cmpx;
int cmps;
int badflg;
int hangflg = 1;
int ecnt = 0;
msgbeg("dotest: %-*s %8.8llX/%8.8llX/%8.8X",taglen,tst->tst_tag,lo,hi,inc);
for (a = lo; a <= hi; a += inc) {
for (b = lo; b <= hi; b += inc) {
cmps = cmpstd(a,b);
cmpx = tst->tst_fnc(a,b);
badflg = (cmps != cmpx);
if (badflg || opt_v) {
if (hangflg) {
hangflg = 0;
printf("\n");
}
printf("%-*s: %s a=%8.8llX b=%8.8llX cmps=%d cmpx=%d\n",
taglen,tst->tst_tag,badflg ? "FAIL" : "PASS",a,b,cmps,cmpx);
if (badflg)
++ecnt;
if (opt_v)
continue;
if (ecnt >= opt_e)
break;
}
}
if (opt_v)
continue;
if (ecnt >= opt_e)
break;
}
if (ecnt || opt_v) {
if (hangflg)
printf("\n");
printf("%-*s: %d errors",taglen,tst->tst_tag,ecnt);
}
msgend();
if (ecnt)
ecnt = 1;
return ecnt;
}
typedef struct {
u32 rng_lo;
u32 rng_hi;
u32 rng_inc;
} rng_t;
rng_t rnglist[] = {
{ .rng_lo = 0x00000000, .rng_hi = 0x000000FF, .rng_inc = 1 },
{ .rng_lo = 0x01000000, .rng_hi = 0xFFFFFFFF, .rng_inc = 0x01000000 },
{ .rng_inc = 0 }
};
int
dorange(rng_t *rng)
{
tst_t *tst;
int code = 0;
for (tst = tstlist; tst->tst_tag != NULL; ++tst) {
code = dotest(tst,rng->rng_lo,rng->rng_hi,rng->rng_inc);
if (! opt_k) {
if (code)
break;
}
}
return code;
}
int
main(int argc,char **argv)
{
int code = 0;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'e':
opt_e = (*cp != 0) ? atoi(cp) : 0x7FFFFFFF;
break;
case 'k':
opt_k = ! opt_k;
break;
case 'L':
opt_L = (*cp != 0) ? atoll(cp) : 65536;
break;
case 'v':
opt_v = ! opt_v;
break;
}
}
setlinebuf(stdout);
if (opt_L == 0)
opt_L = 256;
if (opt_e == 0)
opt_e = 1;
if (opt_v)
opt_e = 0x7FFFFFFF;
// get max length of function name
for (tst_t *tst = tstlist; tst->tst_tag != NULL; ++tst) {
int curlen = strlen(tst->tst_tag);
if (curlen > taglen)
taglen = curlen;
}
// do all test ranges
for (rng_t *rng = rnglist; rng->rng_inc != 0; ++rng) {
code = dorange(rng);
if (code)
break;
}
if (code == 0)
printf("complete\n");
return code;
}
0.000000000 dotest: cmpxor 00000000/000000FF/00000001 (ELAPSED: 0.001531766)
0.001538215 dotest: cmpki 00000000/000000FF/00000001 (ELAPSED: 0.000467471)
0.002008009 dotest: cmpku 00000000/000000FF/00000001 (ELAPSED: 0.000475924)
0.002488059 dotest: cmpxor 01000000/FFFFFFFF/01000000 (ELAPSED: 0.000398438)
0.002888709 dotest: cmpki 01000000/FFFFFFFF/01000000
cmpki : FAIL a=80000000 b=01000000 cmps=1 cmpx=-1
cmpki : 1 errors (ELAPSED: 0.000237286)
0.003127983 dotest: cmpku 01000000/FFFFFFFF/01000000 (ELAPSED: 0.000467515)
complete