简体   繁体   English

按位运算和转移问题

[英]Bitwise operations and shifts problems

I am testing the function fitsBits(int x, int n) on my own and I figure out there is a condition that doesn't fit in this function, what is the problem? 我正在测试函数fitsBits(int x,int n),我发现有一个条件不适合这个函数,有什么问题?

/*
* fitsBits - return 1 if x can be represented as an 
*  n-bit, two's complement integer.
*   1 <= n <= 32
*   Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
*   Legal ops: ! ~ & ^ | + << >>
*   Max ops: 15
*   Rating: 2
*/
int fitsBits(int x, int n) {
   int r, c;
   c = 33 + ~n;
   r = !(((x << c)>>c)^x);
   return r;
}

It seems like it gives the wrong answer in 似乎它给出了错误的答案

fitsBits(0x80000000, 0x20);

It gives me 1, but actually it should be 0... How could I fix it? 它给了我1,但实际上应该是0 ......我怎么能解决它? Thank you! 谢谢!

Left shifts that cause overflow are undefined for signed types. 对于签名类型,未定义导致溢出的左移。 Hence the compiler may optimise (x<<c)>>c as simply x , and the entire function reduces down to return 1; 因此,编译器可以将(x<<c)>>c简化为x ,并且整个函数减少到return 1; .

Probably you want to use unsigned types. 可能你想使用无符号类型。

A second cause of undefined behavior in your code is that c may be greater than or equal to the width of int. 代码中未定义行为的第二个原因是c可能大于或等于int的宽度。 A shift of more than the width of the integer type is undefined behavior. 超过整数类型宽度的移位是未定义的行为。

fitsBits(0x80000000, 0x20);

This function returns 1 , because the first argument of your function is int , which is (in practice these days) a 32 bit signed integer. 这个函数返回1 ,因为函数的第一个参数是int ,它实际上是(实际上是这些天)32位有符号整数。 The largest value that signed 32 bit integer can represent is 0x7FFFFFFF, which is less than the value you are passing in. Because of that your value gets truncated and becomes -0x80000000 , something that 32 bit integer can represent. 签名32位整数可以表示的最大值是0x7FFFFFFF,小于您传入的值。因此,您的值被截断并变为-0x80000000 ,这是32位整数可以表示的值。 Therefore your function returns 1 (yes, my first argument is something that can be represented using 0x20 = 32 bits). 因此,您的函数返回1 (是的,我的第一个参数是可以使用0x20 = 32位表示的东西)。

If you want your function to properly classify number 0x80000000 as something that cannot be represented using 32 bits, you need to change the type of the first argument of your function. 如果您希望函数正确地将数字0x80000000分类为无法使用32位表示的内容,则需要更改函数的第一个参数的类型。 One options would've been using an unsigned int , but from your problem definition it seems like you need to properly handle negative numbers, so your remaining option is long long int , that can hold numbers between -0x8000000000000000 and 0x7FFFFFFFFFFFFFFF . 一个选项可能是使用unsigned int ,但是从您的问题定义中看起来您需要正确处理负数,因此您的剩余选项是long long int ,可以保存-0x80000000000000000x7FFFFFFFFFFFFFFF之间的数字。

You will need to do couple more adjustments: you need to explicitly specify that your constant is of type long long by using LL suffix, and you now need to shift by 64 - c , not by 32 - c : 你需要做更多的调整:你需要通过使用LL后缀明确指定你的常量类型为long long ,现在你需要移动64 - c ,而不是32 - c

#include <stdio.h>

int fitsBits(long long x, int n) {
   long long r;
   int c;
   c = 65 + ~n;
   r = !(((x << c)>>c)^x);
   return r;
}

int main() {
    printf("%d\n", fitsBits(0x80000000LL, 0x20));
    return 0;
}

Link to IDEONE: http://ideone.com/G8I3kZ 链接到IDEONE: http ://ideone.com/G8I3kZ

r = (((x << c)>>c)^x); //This will give you 0, meaning r = 0;

OR 要么

r = !((x << c)>>c);

Your function can be simplified to 您的功能可以简化为

int fitsBits(int x) {

    int r, c; 
    c = 33; 
    r = (((x << c)>>c)^x);

    return r;
}

Note that when NOT( ! ) is brought you're asking for opposite of r 请注意,当NOT( ! )被带来时,你要求r相反

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM