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)?
答案 0 :(得分:6)
这种技术有些惯用。我们简化为a
和b
。我们从:
+----------+----------+
| a | b |
+----------+----------+
我们想向左移一些金额来获得:
+----------+----------+
| a : | b : | c ...
+----------+----------+
|<--x-->| |
->|y |<-
所以X
只是a << k
。 y
是k
的{{1}}个msbs,在单词中右对齐。您可以使用b
获得该结果。
总的来说,你得到:
b >> (32-k)
[注意:此方法仅对1&lt; = a = x | y
= (a << k) | (b >> (32-k))
&lt; = 31有效,因此您的代码实际上是错误的。]
答案 1 :(得分:2)
当a
的位向左移动时,必须填写右端留下的空间。由于a
和b
在概念上相互相邻,因此通过移位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]
k
为3
代表的数字是:
// 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从顶部旋转,低位填充为零)。
现在让我们将其分解为h
和l
...
[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;
}