二进制加法

时间:2019-01-07 11:46:05

标签: c bit-shift

我试图了解C中按位运算符的工作方式,但是我对<<运算符有误解。

我有以下代码:

#include <stdio.h>

int Add(int x, int y);
int Add(int x, int y)
{
    while ( y != 0 )        /// Iterate till there is no carry
    {
        int carry = x & y;  /// carry now contains common set bits of x and y
        x = x ^ y;          /// Sum of bits of x and y where at least one of the bits is not set
        y = carry << 1;     /// Carry is shifted by one so that adding it to x gives the required sum
    }
    return x;
}

int main( void )
{
    printf( "%d", Add( 13, 17 ) );
    return 0;
}

如果我正确理解的话,是这样的:

First Iteration:
|=======================================|
|                                       |
|   while ( y       !=      0     )     |
|   while ( 17      !=      0     )     |
|   while ( 10001   !=      00000 )     |
|                                       |
|   c       =   x       &   y;          |
|   1       =   13      &   17          |
|   00001   =   01101   &   10001       |
|                                       |
|   x       =   x       ^   y           |
|   28      =   13      ^   17          |
|   11100   =   01101   ^   10001       |
|                                       |
|   y       =   c      <<   1           |
|   17      =   1      <<   1           |
|   10001   =   00001  <<   00001       |
|   00010   =   00001  <<   00001       |
|                                       |
|=======================================|

Second Iteration:
|=======================================|
|                                       |
|   while ( y       !=      0     )     |
|   while ( 2       !=      0     )     |
|   while ( 00010   !=      00000 )     |
|                                       |
|   c       =   x       &   y;          |
|   0       =   28      &   2           |
|   00000   =   11100   &   00010       |
|                                       |
|   x       =   x       ^   y           |
|   30      =   28      ^   2           |
|   11110   =   11100   ^   00010       |
|                                       |
|   y       =   c      <<   1           |
|   2       =   0      <<   1           |
|   00010   =   00000  <<   00001       |
|   00000   =   00000  <<   00001       |
|                                       |
|=======================================|

然后Y变成0X返回30

现在在以下代码中我遇到了一个问题:

#include <stdio.h>

int main( void )
{
    int x = 13;
    int y = x << 1; /// 11010 = 01101 << 00001
    x = 0 << 1;     /// 00000 = 00000 << 00001

    printf("y = %d\n", y ); /// 26  | 11010
    printf("x = %d\n", x ); /// 26  | 11010
    return 0;
}

如果我没看错,我们将所有位向左移一位。

int y = x << 1; /// 11010 = 01101 << 00001

但是这里到底发生了什么

x = 0 << 1;     /// 00000 = 00000 << 00001

x是否被清除并充满0 << 1的结果?

2 个答案:

答案 0 :(得分:0)

  

x是否被清除并填充0 << 1的结果?

x仅被分配了表达式0 << 1的值。左移或右移零都保持0

  

那么这意味着第一和第二迭代的表示是正确的吗?

是正确的,除了在以下情况下替换旧值变量(在lhs上)有点令人困惑。

17      =   1      <<   1 
10001   =   00001  <<   00001 

2       =   0      <<   1
00010   =   00000  <<   00001

将其描述为:

y      =   1      <<   1 
y      =   00001  <<   00001 

y       =   0      <<   1
y       =   00000  <<   00001

答案 1 :(得分:0)

n << k is actually n * (2^k) as long as you have enough bits available to keep all of the resulting bits. So 0 << k is 0 * (2^k) = 0 whatever the (positive integer) value of k is.

Note that for usual 32 bit integers, a number on p = 17 bits or more, like 65537 (0x0001_0001), will stop behaving like the multiplication once k is greater or equal to (32+1)-p = (32+1)-17 = 16, as for example 65537 << 16 is 0x1_0001_0000 which is using 33 bits and is truncated to 0x0001_0000 = 65536.
With 65536 << 15 you may also start having strange results as the result, 0x1000_0000, is changing the left most bit, which is the sign bit if you're not using unsigned values...