了解128位数字的左右按位移位

时间:2011-11-30 17:21:00

标签: c++ bit-manipulation

Artichoke101 asked this

  

假设我有一个包含4个32位整数的数组,用于存储128位数字

     

如何在这个128位数字上执行左右移位?"

我的问题与Remus Rusanu给出的答案有关:

void shiftl128 (
    unsigned int& a,
    unsigned int& b,
    unsigned int& c,
    unsigned int& d,
    size_t k)
{
    assert (k <= 128);
    if (k > 32)
    {
        a=b;
        b=c;
        c=d;
        d=0;
        shiftl128(a,b,c,d,k-32);
    }
    else
    {
        a = (a << k) | (b >> (32-k));
        b = (b << k) | (c >> (32-k));
        c = (c << k) | (d >> (32-k));
        d = (d << k);
    }
}

void shiftr128 (
    unsigned int& a,
    unsigned int& b,
    unsigned int& c,
    unsigned int& d,
    size_t k)
{
    assert (k <= 128);
    if (k > 32)
    {
        d=c;
        c=b;
        b=a;
        a=0;
        shiftr128(a,b,c,d,k-32);
    }
    else
    {
        d = (c << (32-k)) | (d >> k); \
        c = (b << (32-k)) | (c >> k); \
        b = (a << (32-k)) | (b >> k); \
        a = (a >> k);
    }
}

让我们只关注一个班次,左移说。具体来说,

a = (a << k) | (b >> (32-k));
b = (b << k) | (c >> (32-k));
c = (c << k) | (d >> (32-k));
d = (d << k);

如何将128位数字移位?我理解什么是比特移位,&lt;&lt;向左移位,(8位数)像00011000左移2是01100000.同样适用于右移,但是向右移动。那么单一的'#34;管道&#34; |是OR意味着任何32位数字中的任何1都将出现在结果中。

a = (a << k) | (b >> (32-k))如何正确地移动128位数字的第一部分(32)?

6 个答案:

答案 0 :(得分:6)

这种技术有些惯用。我们简化为ab。我们从:

开始
+----------+----------+
|    a     |    b     |
+----------+----------+

我们想向左移一些金额来获得:

+----------+----------+
|  a    :  |  b    :  |  c  ...
+----------+----------+
|<--x-->|  |
      ->|y |<-

所以X只是a << kyk的{​​{1}}个msbs,在单词中右对齐。您可以使用b获得该结果。

总的来说,你得到:

b >> (32-k)

[注意:此方法仅对1&lt; = a = x | y = (a << k) | (b >> (32-k)) &lt; = 31有效,因此您的代码实际上是错误的。]

答案 1 :(得分:2)

a的位向左移动时,必须填写右端留下的空间。由于ab在概念上相互相邻,因此通过移位a的位而留下的空白将被从末端移位的位填充b。表达式b >> (32-k)计算从b移出的位。

答案 2 :(得分:1)

您需要记住,在转移时,可以接受“丢失”数据。

了解转变的最简单方法是想象一个窗口。例如,让我们处理字节。您可以将字节视为:

  0 0 0 0 0 0 0 0 a b c d e f g h 0 0 0 0 0 0 0 0
                 [      B        ]

现在,转移只是移动这个窗口:

  0 0 0 0 0 0 0 0 a b c d e f g h 0 0 0 0 0 0 0 0
 [     B >> 8    ]
   [     B >> 7    ]
     [     B >> 6    ]
       [     B >> 5    ]
  0 0 0 0 0 0 0 0 a b c d e f g h 0 0 0 0 0 0 0 0
         [     B >> 4    ]
           [     B >> 3    ]
             [     B >> 2    ]
               [     B >> 1    ]
  0 0 0 0 0 0 0 0 a b c d e f g h 0 0 0 0 0 0 0 0
                   [     B << 1    ]
                     [     B << 2    ]
                       [     B << 3    ]
                         [     B << 4    ]
  0 0 0 0 0 0 0 0 a b c d e f g h 0 0 0 0 0 0 0 0
                           [     B << 5    ]
                             [     B << 6    ]
                               [     B << 7    ]
                                 [     B << 8    ]
  0 0 0 0 0 0 0 0 a b c d e f g h 0 0 0 0 0 0 0 0

如果你看一下箭头的方向,你可以把它想象成一个固定的窗口和一个移动的内容......就像你喜欢的手机触摸屏一样!

那么,表达式a = (a << k) | (b >> (32-k))中发生了什么?

  • a << k选择32 - k最右边的a位并向左移动,在右侧创建k 0的空格
  • b >> (32-k)选择k最左边的b位并向右移动,在左侧创建32 - k 0的空格
  • 两者合并在一起

回到使用字节长度的叮咬:

  • 假设a[a7, a6, a5, a4, a3, a2, a1, a0]
  • 假设b[b7, b6, b5. b4, b3, b2, b1, b0]
  • 假设k3

代表的数字是:

// before
 a7 a6 a5 a4 a3 a2 a1 a0 b7 b6 b5 b4 b3 b2 b1 b0
[           a           ]
                        [           b           ]

// after (or so we would like)
 a7 a6 a5 a4 a3 a2 a1 a0 b7 b6 b5 b4 b3 b2 b1 b0
         [           a           ]
                                 [           b           ]

所以:

  • a << 3确实变为a4 a3 a2 a1 a0 0 0 0
  • b >> (8 - 3)变为0 0 0 0 0 b7 b6 b5
  • |合并,我们得到a4 a3 a2 a1 a0 b7 b6 b5

冲洗并重复:)

答案 3 :(得分:0)

请注意,在else情况下,k保证为32或更小。因此,较大数字的每个部分实际上可以移位k位。但是,向左或向右移动会使k高/低位为0.要移动整个128位数,您需要用相邻数字“移出”的位填充这些k位。

在左移k的情况下,较高数的k个较低位需要用较低数的k个较高位填充。为了获得这些高k位,我们将该(32位)数字右移32-k位,现在我们将这些位置于正确位置以从较高位置填充零k位。

BTW:上面的代码假设unsigned int正好是32位。那不便携。

答案 4 :(得分:0)

为了简化,考虑一个16位无符号短路,我们将高字节和低字节分别存储为unsigned char h, l。 为了进一步简化,我们只需将其向左移一位,看看情况如何。

我把它写成16个连续的位,因为那是我们的建模:

[h7 h6 h5 h4 h3 h2 h1 h0 l7 l6 l5 l4 l3 l2 l1 l0]

所以,[h, l] << 1将是

[h6 h5 h4 h3 h2 h1 h0 l7 l6 l5 l4 l3 l2 l1 l0 0]

(顶部位,h7从顶部旋转,低位填充为零)。 现在让我们将其分解为hl ...

[h, l] = [h6 h5 h4 h3 h2 h1 h0 l7 l6 l5 l4 l3 l2 l1 l0 0]
=> h = [h6 h5 h4 h3 h2 h1 h0 l7]
     = (h << 1) | (l >> 7)

答案 5 :(得分:0)

我在小端环境中对128位数的逻辑左移的变体:

typedef struct { unsigned int component[4]; } vector4; 
vector4 shift_left_logical_128bit_le(vector4 input,unsigned int numbits) {
    vector4 result;
    if(n>=128) {
         result.component[0]=0;
         result.component[1]=0;
         result.component[2]=0;
         result.component[3]=0;
         return r;
    }
    result=input;
    while(numbits>32) {
        numbits-=32;
        result.component[0]=0;
        result.component[1]=result.component[0];
        result.component[2]=result.component[1];
        result.component[3]=result.component[2];
    }
    unsigned long long temp;
    result.component[3]<<=numbits;
    temp=(unsigned long long)result.component[2];
    temp=(temp<<numbits)>>32;
    result.component[3]|=(unsigned int)temp;
    result.component[2]<<=numbits;
    temp=(unsigned long long)result.component[1];
    temp=(temp<<numbits)>>32;
    result.component[2]|=(unsigned int)temp;
    result.component[1]<<=numbits;
    temp=(unsigned long long)result.component[0];
    temp=(temp<<numbits)>>32;
    result.component[1]|=(unsigned int)temp;
    result.component[0]<<=numbits;
    return result;
}