void rotate( unsigned long mask[], int rotateCnt );
此函数将当前64位掩码(mask [])旋转rotateCnt
个位置。如果rotateCnt
为正,则向左旋转;如果rotateCnt
为负数,则向右旋转。只有rotateCnt
的低6位才能用于rotateCnt
。
但是我必须在2个32位寄存器中进行旋转,模拟1个64位寄存器,逻辑上在两个32位寄存器上执行64位操作。他们告诉我要做2个循环,但我想不出来了?任何h
答案 0 :(得分:4)
当您使用x86时,请查看shld and shrd。你不需要循环(为什么他们要求循环超出我的范围。)
<强>更新强>
这是一个DevStudio 2005样式函数,它使用内联汇编程序来执行您想要的操作。如果没有完全理解这一切是如何起作用的话(尤其是负面计数如何正确旋转),请不要将此作为解决方案提出来,因为您的教师很容易发现您在不知道其工作原理的情况下复制了这一点(即教师:“这是怎么回事?“,你:”Errr ......“=&gt;失败)。
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
}
}
答案 1 :(得分:1)
对此可能有更快的说明,但这里的想法是......如果你向左转:
从高阶寄存器中取出最重要的rotateCnt
位,将它们右移32-rotateCnt
位,并将结果存储在某处
将高阶寄存器移位rotateCnt
位
从低位寄存器中取出最重要的rotateCnt
位,将它们向左移位32-rotateCnt
位,并将结果添加到高位寄存器
将低位寄存器中的剩余位移位rotateCnt
位并添加在步骤1中保存的位
我相信你可以看到如何将这个过程扩展到任意数量的寄存器。如果rotateCnt
可能大于32位,则必须更加努力,特别是在一般情况下(n个寄存器而不是2个寄存器)。有一点可能有用,就是注意左移n位与右移(size-n)位相同。
从你的评论中,我看到你应该使用一个循环。您始终可以一次1位地应用上述旋转过程以进行rotateCnt迭代。在这种情况下,您显然会将上述说明中的rotateCnt
更改为1
。
答案 2 :(得分: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
要使用此基本操作旋转多个位置,只需循环适当的次数。
请注意,通过应用正确的位掩码和移位集,可以在没有任何循环的情况下完成此操作。基本上你可以在没有循环的情况下获得将在一次拍摄中执行单词的所有位。循环版本可能更容易实现 - 如果您决定将其改进为非循环版本,您可以考虑首先使用它并将其用作验证测试。
答案 3 :(得分: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位乘法一样,只需要比其他处理器更多的代码,但它是非常可行的。