C中的按位运算:检查数字是否为正数

时间:2018-06-12 23:57:54

标签: c math bit-manipulation

x是一个int,

当不涉及0时,我应该能够得到正确的结果。为了解释0案例,我添加了"& x",我相信现在应该返回一个数字是正数iff x> 0和x不为0(因为在c中,0以外的任何数字的计算结果为真,对吗?)

但是,在运行我的测试时,它说它无法将0x7fffffff评估为正,我不确定为什么!

这是我的代码:

int mask = 0x1;
x = x >> 31;
int lsb = mask & x;
return ( (lsb) ^ 0x1) & (x) )

编辑:我已经通过将代码更改为下面的代码解决了问题!反馈仍然非常受欢迎,或者您可能发现任何问题。

int mask = 0x1;
int lsb = (x >> 31) & mask;
int result = !(lsb ^ 0x1);
return !(result | !x);

5 个答案:

答案 0 :(得分:1)

https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign

从技术上讲,int在不同的机器上可能有不同的大小;使用来自int32_t的C99 inttypes.h可能有助于提高可移植性。它甚至可能不会以您期望的格式进行编码,Are there any non-twos-complement implementations of C?

真正便携的简单方法当然是

static int is_positive(const int a) {
    return a > 0;
}

编译器可能会更好地优化它。

编辑:从评论中,我想出了这个;我试图让它与int - 大小无关。它与您自己的风格非常相似,检查数字是负数还是零,并反转。

#include <stdio.h>  /* printf */
#include <limits.h> /* INT_ */
#include <assert.h> /* assert */

/** Assumes a is a 2's-compliment number
 and ~INT_MAX = 0b100..00, (checks if negative.) */
static int is_positive(const int a) {
    unsigned b = a;
    return !((b & ~INT_MAX) | !b);
}

static int is_really_positive(const int a) {
    return a > 0;
}

static void test(const int a) {
    printf("Number %d. Is positive %d.\n", a, is_positive(a));
    assert(is_positive(a) == is_really_positive(a));
}

int main(void) {
    test(INT_MIN);
    test(-2);
    test(-1);
    test(0);
    test(1);
    test(2);
    test(INT_MAX);
    return 0;
}

也相关,https://stackoverflow.com/a/3532331/2472827

答案 1 :(得分:1)

如果你知道代表是2's complement,那么你可以这样做:

#include <stdio.h>

#define IS_NEG(a)   (!!((1 << 31) & (a)))

int main(void)
{
    int n;

    while(1) {
        scanf("%d", &n);
        printf("negative: %d\n", IS_NEG(n));
    }
    return 0;
}

说明:

  1. (1 << 31)将获取数字1并将其向左移动31次,从而为您提供1000 0000 0000 0000 0000 0000 0000 0000。如果您不想使用班次,也可以使用0x80000000
  2. & (a)使用那个大二进制数进行逐位测试。由于AND操作仅在两个操作数均为TRUE时返回TRUE,因此只有当您的数字为负数(在2&#39的补码表示中)时才会返回返回TRUE
  3. !!(...)这个双重否定说明了这样一个事实:当你按位进行AND时,如果数字真的是负数,表达式的返回值将是(1 << 31)。所以我们将它反转(给我们零),而不是再反转它(给我们1)。因此,这可以确保我们获得ZERO或ONE作为最终结果。
  4. IS_NEG将在正数AND 0上返回0,并在所有负数上返回1。
  5. 由于当数字为负数时MSB将为1,因此只需测试该位。请注意,这仅适用于32位整数(因此您必须使用sizeof(int)进行检查。如果数字为负数,则示例返回1,但将其重新编译为没有问题返回1表示正数。

    如果这不能解决问题,请告诉我。据我了解,您只想测试任何给定的int是否为正/负。

    <小时/> 修改:根据评论,我制作了一个程序来帮助您了解正在发生的事情。

    #include <stdio.h>
    
    #define IS_NEG(a)   (!!(0x80000000 & (a)))
    
    char buf[65];
    /* converts an integer @n to binary represention of @bits bits */
    char *bin(int n, unsigned int bits)
    {
        char *s = buf;
        for(bits = (1 << (bits - 1)); bits > 0; bits = bits >> 1)
            /* look! double negation again! Why this? :) */
            *s++ = !!(n & bits) + 48;
    
        *s = 0;
        return buf;
    }
    
    int main(void)
    {
        /* R will be our partial result through-out the loop */
        int r, n;
    
        while(1) {
            /* get the number */
            scanf("%d", &n);
    
            /* this is the inner part of the macro
             * after this, we could say IS_NEG "becomes"
             * (!!(r))
             */
            r = n & 0x80000000;
            printf("n & 0x80000000: 0x%x\n", r);
            printf("  n = %s\n", bin(n, 32));
            printf("  r = %s\n", bin(r, 32));
    
            /* now we print what R is, so you see that the bitwise AND will
             * return 0x80000000 on negative numbers. It will also print
             * the NEGATION of R...
             * 
             * After the printf(), we just assign the negated value to R.
             */
            printf("r = 0x%x, !r = 0x%x\n", r, !r);
            r = !r;
            printf("  r = %s\n", bin(r, 32));
            /* After this, IS_NEG "becomes" (!(r)) */
    
            /* In the MACRO, this would be the second negation. */
            printf("r = 0x%x, !r = 0x%x\n", r, !r);
            r = !r;
            printf("  r = %s\n", bin(r, 32));
    
            /* Now, if R is 0, it means the number is either ZERO or 
             * POSITIVE.
             *
             * If R is 1, then the number is negative
             */
        }
        return 0;
    }
    

答案 2 :(得分:1)

鉴于您的评论中允许的运算符! ~ & ^ | + << >>,编辑:使用后来的无强制转换约束,只有第二种替代方案适合:

static int is_positive(unsigned x)
{
        return ~x+1 >> (CHAR_BIT*sizeof x-1);
}

这里是交易:在C中非常仔细地指定转换为无符号:如果无符号类型中的有符号值不可表示,则添加一个加上无符号类型中可表示的最大值(或减去,不知道)是什么促使他们将这种可能性包括在传入的值中,直到结果 可表示为止。

因此结果仅取决于传入值,而不是其表示。无论怎样,-1都会转换为UINT_MAX。这是正确的,因为the universe itself runs on twos-complement notation。这也使得转换成为大多数CPU上的简单无操作重新解释只是一个奖励。

答案 3 :(得分:0)

您可以使用按位或移位进行32位宽零或非零测试,如下所示:

int t;
t = x | (x>>16);
t = t | (t >> 8);
t = t | (t >> 4);
t = t | (t >> 2)
t = (t | (t>>1)) & 1;

这将t设置为x的低32位的“OR”,并且当且仅当低32位全为零时才为0。如果int类型为32位或更少,则相当于(x != 0)。您可以将它与您的符号位测试结合起来:

return t & (~x >> 31);

答案 4 :(得分:0)

检查给定数字是正数还是负数。正如您所提到的,xint&amp;我假设它的32位长签名int。例如

int x = 0x7fffffff;

以上x如何用二进制

表示
 x  =>  0111 1111 | 1111 1111 | 1111 1111 | 1111 1111 
        |                                           |
        MSB                                         LSB

现在使用按位opaertor检查给定数字是正数还是负数,只需找出最后状态(MSB或31st(longint)或第15(short int))位状态,无论是0还是{{1如果找到最后一位为1,则表示给定数字为正数,否则为负数。

现在如何检查最后一位(第31位)状态?将最后(第31位)位移到0位并执行按位AND&amp;使用0th进行操作。

1

现在如何编程

x     =>  0111 1111 | 1111 1111 | 1111 1111 | 1111 1111
x>>31 =>  0000 0000 | 0000 0000 | 0000 0000 | 0000 0000  
          --------------------------------------------- 
                                                      &
  1   =>  0000 0000 | 0000 0000 | 0000 0000 | 0000 0001
          ---------------------------------------------
          0000 0000 | 0000 0000 | 0000 0000 | 0000 0000 => its binary of zero( 0 ) so its a positive number

并调用static inline int sign_bit_check(int x) { return (x>>31) & 1; } 之类的

sign_bit_check()