【发布时间】:2011-05-13 18:48:46
【问题描述】:
假设我有一个由 4 个 32 位整数组成的数组,用于存储 128 位数字
如何对这个 128 位数字进行左移和右移?
谢谢!
【问题讨论】:
-
为什么不使用 2
int64_t?它会让事情变得比 4int32_t简单得多
标签: c++ c bit-manipulation bitwise-operators bit-shift
假设我有一个由 4 个 32 位整数组成的数组,用于存储 128 位数字
如何对这个 128 位数字进行左移和右移?
谢谢!
【问题讨论】:
int64_t?它会让事情变得比 4 int32_t 简单得多
标签: c++ c bit-manipulation bitwise-operators bit-shift
与uint128 合作?如果可以,请使用专门为此设计的 x86 SSE 指令。 (然后,当您对值进行位移后,您就可以进行其他 128 位操作了……)
SSE2 位移平均需要约 4 条指令,一个分支(一个 case 语句)。移位超过 32 位也没有问题。执行此操作的完整代码是使用 gcc 内在函数而不是原始汇编程序,位于 sseutil.c (github: "Unusual uses of SSE2") 中——它比粘贴在这里的意义要大一些。
许多人使用 SSE2 的障碍是班次操作需要立即(恒定)班次计数。你可以用一点 C 预处理器来解决这个问题 (wordpress: C preprocessor tricks)。之后,你就有了这样的操作序列:
LeftShift(uint128 x, int n) = _mm_slli_epi64(_mm_slli_si128(x, n/8), n%8)
对于 n = 65..71, 73..79, ... 121..127 ...在两条指令中完成整个转变。
【讨论】:
void shiftl128 (
unsigned int& a,
unsigned int& b,
unsigned int& c,
unsigned int& d,
size_t k)
{
assert (k <= 128);
if (k >= 32) // shifting a 32-bit integer by more than 31 bits is "undefined"
{
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) // shifting a 32-bit integer by more than 31 bits is "undefined"
{
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);
}
}
【讨论】:
do/while(0) 或类似名称中)。此外,宏似乎执行移位操作,但名称暗示旋转 - 如果我遇到使用它们的代码,我会发现这令人困惑。任何考虑使用它们的人都应该注意解决问题。或者使用函数版本。
if (k >= 32)。
为什么不使用位集而不是使用 128 位数字?使用 bitset,您可以调整想要的大小。另外,您可以对其执行相当多的操作。
您可以在此处找到有关这些的更多信息:
http://www.cppreference.com/wiki/utility/bitset/start?do=backlink
【讨论】:
首先,如果您要移位n 位并且n 大于或等于32,则除以32 并移位整数。这应该是微不足道的。现在剩下的班次计数从 0 到 31。如果为零,请早点返回,就完成了。
对于每个整数,您需要将剩余的n 移动,然后将相邻的整数移动相同的量并合并每个整数的有效位。
【讨论】:
既然您提到您将 128 位值存储在一个由 4 个整数组成的数组中,您可以执行以下操作:
void left_shift(unsigned int* array)
{
for (int i=3; i >= 0; i--)
{
array[i] = array[i] << 1;
if (i > 0)
{
unsigned int top_bit = (array[i-1] >> 31) & 0x1;
array[i] = array[i] | top_bit;
}
}
}
void right_shift(unsigned int* array)
{
for (int i=0; i < 4; i++)
{
array[i] = array[i] >> 1;
if (i < 3)
{
unsigned int bottom_bit = (array[i+1] & 0x1) << 31;
array[i] = array[i] | bottom_bit;
}
}
}
【讨论】: