【问题标题】:Bitwise shift operation on a 128-bit number对 128 位数字进行按位移位操作
【发布时间】:2011-05-13 18:48:46
【问题描述】:

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

如何对这个 128 位数字进行左移和右移?

谢谢!

【问题讨论】:

标签: c++ c bit-manipulation bitwise-operators bit-shift


【解决方案1】:

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 ...在两条指令中完成整个转变。

【讨论】:

  • 您应该显示相关代码而不是链接到场外。我厌倦了浏览您的宏实现,但可能需要展开它以使访问者更清楚。
【解决方案2】:
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);
    }
}

【讨论】:

  • k > 32 失败。你认为函数不会比宏更好吗?
  • @Martin:你是对的,但在这方面还没有超过 32 岁。
  • @Remus Rusanu 和马丁:非常感谢!
  • 除了提到的大于32的移位问题外,宏版本还有一些常见的宏问题:使用的参数没有完全括号,如果参数不是32-可能会出现不良行为位类型或有符号类型,宏不是“语句安全”(它们应该被包装在 do/while(0) 或类似名称中)。此外,宏似乎执行移位操作,但名称暗示旋转 - 如果我遇到使用它们的代码,我会发现这令人困惑。任何考虑使用它们的人都应该注意解决问题。或者使用函数版本。
  • @Remus Rusanu:这段代码仍然有一个错误。递归的条件应该是if (k &gt;= 32)
【解决方案3】:

为什么不使用位集而不是使用 128 位数字?使用 bitset,您可以调整想要的大小。另外,您可以对其执行相当多的操作。

您可以在此处找到有关这些的更多信息:

http://www.cppreference.com/wiki/utility/bitset/start?do=backlink

【讨论】:

  • @C Johnson 我同意可以使用 bitset,但我更多地从逻辑角度看待它,并将这 4 个 32 位整数作为约束
【解决方案4】:

首先,如果您要移位n 位并且n 大于或等于32,则除以32 并移位整数。这应该是微不足道的。现在剩下的班次计数从 0 到 31。如果为零,请早点返回,就完成了。

对于每个整数,您需要将剩余的n 移动,然后将相邻的整数移动相同的量并合并每个整数的有效位。

【讨论】:

    【解决方案5】:

    既然您提到您将 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;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 2022-11-17
      相关资源
      最近更新 更多