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