1
void rotate( unsigned long mask[], int rotateCnt ); 

此函数按位旋转当前的 64 位掩码 (mask[]) rotateCnt。如果rotateCnt为正,则向左旋转;如果rotateCnt是负数,向右旋转。rotateCnt仅应使用的低 6 位rotateCnt

但我必须在模拟 1 个 64 位寄存器的 2 个 32 位寄存器中进行轮换,在两个 32 位寄存器之间逻辑执行 64 位操作。他们告诉我做 2 个循环,但我想不通?任何小时

4

4 回答 4

4

当您使用 x86 时,请查看shld 和 shrd。你不需要循环(为什么他们要求循环超出了我的范围)。

更新

这是一个 DevStudio 2005 风格的函数,它使用内联汇编器来做你想做的事。不要在没有完全理解它是如何工作的情况下将其作为解决方案提出(尤其是负数如何进行右旋转),因为您的老师很容易发现您在不知道它是如何工作的情况下复制了它(即老师:“这是如何工作的?”,你:“Errr ...” => FAIL)。

void Rotate
(
  unsigned *value, // pointer to two 32bit integers
  int count        // number of bits to rotate: >= 0 left, < 0 = right
)
{
  __asm
  {
    mov esi,value
    mov eax,[esi]
    mov edx,[esi+4]
    mov ecx,count
    mov ebx,eax
    shld eax,edx,cl
    shld edx,ebx,cl
    test cl,32
    jz noswap
    xchg edx,eax
noswap:
    mov [esi],eax
    mov [esi+4],edx
  }
}
于 2012-05-03T15:20:27.020 回答
1

单个位循环只是一个位移位,其中一个字的进位被应用于下一个字,特殊情况是高位字的进位被应用于低位字。

它可以帮助您考虑在某些情况下需要发生什么。我将在下面使用 4 位字,并假设旋转在左侧;相同的概念适用于您可能使用的任何字长:

// Note '-' in the carry column means "don't care"
//
// starting value (in binary):

              'high'             'low'
     carry     word     carry     word

        -     1 0 0 0     -     1 0 0 1

//  after shift left of each word:

        1     0 0 0 0      1    0 0 1 0

//  apply the carry out of the low word
//      to the high word:

        1     0 0 0 1      -    0 0 1 0    

//  apply the carry out of the high word
//      to the low word

        -     0 0 0 1      -    0 0 1 1    

要使用这个基本操作来旋转多个位置,只需循环适当的次数。

请注意,这可以通过应用正确的位掩码和移位集来完成,而无需任何循环。基本上,您无需循环即可一次获得将执行单词的所有位。循环版本可能更容易实现 - 如果您决定将其改进为非循环版本,您可能会考虑先执行此操作并将其用作验证测试。

于 2012-05-03T15:32:20.557 回答
1

可能有更快的说明,但这里的想法......如果你向左旋转:

  1. rotateCnt从高位寄存器中取出最高有效位,将它们右移32-rotateCnt,并将结果存储在某处

  2. 将高位寄存器左移rotateCnt一位

  3. rotateCnt从低位寄存器中取出最高有效位,将它们左移32-rotateCnt,并将结果添加到高位寄存器

  4. 将低位寄存器中的剩余位向左移动rotateCnt位并添加您在步骤 1 中保存的位

我相信您可以看到如何将此过程扩展到任意数量的寄存器。如果rotateCnt可以大于 32 位,您将不得不更加努力,尤其是在一般情况下(n 个寄存器而不是 2 个)。可能有帮助的一件事是注意左移 n 位与右移 (size-n) 位相同。

从您的评论中,我看到您应该使用循环。对于 rotateCnt 迭代,您始终可以一次应用上述旋转过程 1 位。在这种情况下,您显然rotateCnt会将上面的描述更改为1.

于 2012-05-03T15:22:42.603 回答
0

例如,考虑如何在 C 中执行此操作,然后将其转换为 asm。

例如,使用 32 位变量进行一次左移,假设 ra 是高 32 位,rb 是低位

if(rb&0x80000000) { ra<<=1; ra|=1; rb<<=1 }
else              { ra<<=1; rb<<=1; }

对于旋转,您可能会按照这些方式做一些事情

if(rb&0x80000000)
{
  if(ra&0x80000000) { ra<<=1; ra|=1; rb<<=1: rb|=1; }
  else              { ra<<=1; ra|=1; rb<<=1; }
}
else
{
  if(ra&0x80000000) { ra<<=1; rb<<=1: rb|=1; }
  else              { ra<<=1; rb<<=1; }
}

然后,您可以围绕其中一个循环并执行 N 次。

或者说左移 8 位

ra=(ra<<8)|(rb>>(32-8));
rb<<=8;

或者说左移 N 位

ra=(ra<<=n)|(rb>>(32-n));
rb<<=n;

或者 n 位向左旋转(这与 32-n 位向右旋转相同)(有些处理器只有向右旋转而左侧是虚拟的,反之亦然)。

temp=ra>>(32-n);
ra=(ra<<=n)|(rb>>(32-n));
rb=(rb<<<=n)|temp;

然后查看指令集,看看哪些是可用的并且与你正在做的相匹配。

简而言之,要移位位,您需要将位放在一侧并将其放入下一位。如果您将自己对齐在变量或寄存器之类的某个边界上,那么您从一侧获取位并将其转移到另一侧没有区别,它可能需要更多代码,因为指令集或编程语言不直接支持它并不意味着您不能做。就像您可以在没有乘法指令的情况下在 8 位处理器上执行 2048 位乘法一样,只需要比其他处理器更多的代码,但它非常可行。

于 2012-05-03T17:00:21.357 回答