C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++右移运算符的一个小坑

C++右移运算符的一个小坑及解决

作者:玄黄问道

文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数

我遇到了这么一个函数

template<typename T>
unsigned char countByt(T byt)
{
    unsigned char num=0;
    while(byt)
    {
        num += (byt & 0x01);
        byt >>= 1;
        // cout<<hex<<byt<<endl;
    }
    return num;
}

很明显,这个函数是统计byt二进制下1的个数。

没毛病

但当我输入负数的时候,就会陷入死循环。

用那行注释中的东西输出中间过程:

由此可以看到

我对代码进行如下修改:

template<typename T>
unsigned char countByt(T byt)
{
    unsigned char num=0;
    while(byt)
    {
        num += (byt & 0x01);
        byt/=2;
        //byt >>= 1;
        //cout<<hex<<byt<<endl;
    }
    return num;
}

负数的结果:

这个时候,统计的是其所对应正数的1的个数。

也很好理解

补码是其正数按位取反再加1

可以看到,一个数的正和负,它们最后一位一定是一样的!

1、如果我们用/=2来的话:

-1/2=0

那结果跟正数统计是一样的。

2、如果我们用>>=1的话:

-1:ffffffff

右移一位后,由于左侧补1,

还是:ffffffff

死循环就发生了。

但我在实验的时候又发现了有趣的一点:

    int n;
    while(cin>>n)
    {
        cout<<(n>>1)<<endl;

    }
1
0
-1
-1

2
1
-2
-1


3
1
-3
-2


9
4
-9
-5


8
4
-8
-4

可以看到:>>=1 等价于除以2后的(向下)取整。

而 / 运算符,是先对正数部分取整,再加符号。

因此对两个int变量a,b:

a/b不一定小于 等于(double)a/b;

    
    while(cin>>a>>b)
        cout<<((a/b)<=((double)a/b))<<endl;
        

输出:

5 3
1
-5 3
0
-5 -3
1
5 -3
0

总结

当使用右移运算符的时候,一定要注意输入为负数的可能!在负数下 >>1 和 /=2 并不等价!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文