【问题标题】:Left shift of only part of a number仅数字的一部分左移
【发布时间】:2010-12-09 11:54:10
【问题描述】:

我需要找到以下 C 代码的最快等价。

int d = 1 << x; /* d=pow(2,x) */
int j = 2*d*(i / d) + (i % d);

我的想法是左移 i 的高 32 - x 位。
例如以下 x=5 的 i:
1010 1010 1010 1010
将变为:
0101 0101 0100 1010
有没有为此的汇编命令?如何快速执行此操作?

【问题讨论】:

  • 您应该使用unsigned,而不是int。您的示例具有带符号值的未定义行为(溢出)。

标签: c optimization assembly x86


【解决方案1】:

分区很慢:

int m = (1 << x) - 1;
int j = (i << 1) - (i & m);

更新

或者可能更快:

int j = i + (i & (~0 << x));

【讨论】:

  • 非常好。我完全错过了在那里提供最佳优化的数学方面。
【解决方案2】:

x86 32 位汇编(AT&T 语法):

/* int MaskedShiftByOne(int val, int lowest_bit_to_shift) */
mov 8(%esp), %ecx
mov $1, %eax
shl %ecx, %eax            ; does 1 << lowest_bit_to_shift
mov 4(%esp), %ecx
dec %eax                  ; (1 << ...) - 1 == 0xf..f (lower bitmask)
mov %eax, %edx
not %edx                  ; complement - higher mask
and %ecx, %edx            ; higher bits
and %ecx, %eax            ; lower bits
lea (%eax, %edx, 2), %eax ; low + 2 * high
ret

这应该适用于 Linux 和 Windows。

编辑:i + (i &amp; (~0 &lt;&lt; x)) 更短:

mov 4(%esp), %ecx
mov $-1, %eax
mov 8(%esp), %edx
shl %edx, %eax
and %ecx, %eax
add %ecx, %eax
ret

士气:永远不要从组装开始。如果你真的需要它,反汇编高度优化的编译器输出......

【讨论】:

    【解决方案3】:

    左移一位 x 高位。

    unsigned i = 0xAAAAu;
    int x = 5;
    i = (i & ((1 << x) - 1)) | ((i & ~((1 << x) - 1)) << 1); // 0x1554A;
    

    一些解释:

    (1 &lt;&lt; x) - 1 将掩码设为零高位 32 - x

    ~((1 &lt;&lt; x) - 1) 将掩码设为零低 x 位。

    在位归零后,我们将上半部分和or 一起移动。

    Codepad 上试试这个。

    【讨论】:

      【解决方案4】:
      int m = (1 << x) - 1;
      int j = ((i & ~m) << 1) | (i & m);
      

      没有汇编命令可以做你想做的事,但我给出的解决方案更快,因为它避免了除法。

      【讨论】:

      • 被它打败了几秒钟 :) 我认为我的速度稍微快一些,因为它避免了两次计算 ((1&lt;&lt;x)-1)
      • 我认为优化器会解决这个问题。不过你的更干净=)
      • 是的,您对优化器的看法是正确的。尽管我知道编译器可以疯狂地优化代码,但我已经编程了足够长的时间,以至于我仍然在这里和那里不断地手动优化代码。也不是很糟糕,因为它通常倾向于更简洁的代码。
      【解决方案5】:

      英特尔语法:

      mov ecx,[esp+4]      ;ecx = x
      mov eax,[esp+8]      ;eax = i
      
      ror eax,cl
      inc cl
      clc
      rcl eax,cl
      ret
      

      道德:高度优化的编译器输出...不是。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-03
        • 2014-06-17
        • 1970-01-01
        • 2012-05-17
        • 1970-01-01
        • 2021-01-28
        • 2022-10-14
        • 1970-01-01
        相关资源
        最近更新 更多