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

この関数は、現在の 64 ビット マスク (mask[]) をrotateCnt桁ごとにローテーションします。が正の場合、rotateCnt左に回転します。が負の場合、rotateCnt右に回転します。には、 の下位 6 ビットのみをrotateCnt使用する必要がありrotateCntます。

しかし、1 つの 64 ビット レジスタをシミュレートする 2 つの 32 ビット レジスタでローテーションを実行し、2 つの 32 ビット レジスタで 64 ビット操作を論理的に実行する必要があります。彼らは私に 2 つのループを行うように言われましたが、私はこれを理解できませんか? 任意の時間

4

4 に答える 4

4

x86 を使用しているので、 shld と shrdを見てください。ループは必要ありません (ループを要求した理由はわかりません)。

アップデート

これは、インライン アセンブラを使用して必要なことを行う DevStudio 2005 スタイルの関数です。すべてがどのように機能するか (特に、負の数が右回転する方法) を完全に理解することなく、これを解決策として提示しないでください。なぜなら、教師は、それがどのように機能するかを知らずにこれをコピーしたことに非常に簡単に気付くからです (つまり、教師: "これはどのように機能しますか?", You: "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

これにはおそらくもっと簡単な手順がありますが、アイデアは次のとおりです...左に回転している場合:

  1. 上位レジスタから最上位rotateCntビットを取得し、それらを右32-rotateCntビットにシフトし、結果をどこかにスタッシュします

  2. rotateCnt上位レジスタをビット単位で左にシフトする

  3. 下位レジスタから最上位rotateCntビットを取得し、それらを左32-rotateCntビットにシフトし、結果を上位レジスタに追加します

  4. 下位レジスタの残りのビットをビット単位で左にシフトしrotateCnt、手順 1 で保存したビットを追加します。

このプロセスを任意の数のレジスタに拡張する方法がわかるはずです。rotateCnt32 ビットを超える可能性がある場合は、特に一般的な場合 (2 つではなく n レジスタ)、もう少し手間がかかる必要があります。n ビット左にシフトすることは、(size-n) ビットだけ右にシフトすることと同じであることに注意してください。

あなたのコメントから、ループを使用することになっていることがわかります。上記の回転手順は、rotateCnt 反復に対して一度に 1 ビットずつ適用できます。その場合、明らかにrotateCnt上記の説明を に変更し1ます。

于 2012-05-03T15:22:42.603 に答える
1

シングル ビット ローテーションは、上位ワードのキャリー アウトが下位ワードに適用される特殊なケースを使用して、1 つのワードのキャリー アウトが次のワードに適用される単純な 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 に答える
0

たとえば、C でこれを行う方法を考えてから、それを asm に変換します。

たとえば、ra が上位 32 ビットで rb が下位であると仮定すると、32 ビット変数を使用して左に 1 ビット シフトします。

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 に答える