[Atelier Blue アトリエブルー]Homeプログラミング IL(CIL,MSIL)>論理演算・シフト演算・符号なし除算余り算

論理演算・シフト演算・符号なし除算余り算

今回は前回の経験を生かしつつ、論理演算・シフト演算・符号なし除算余り算について学びましょう。

Console.WriteLine

本題の前に、Console.WriteLineに用意されているメソッドをいくつか紹介しておきます。

int16、int8などはそのまま出力できないので注意です。

論理演算

論理演算は、引数を一つだけとるnotと、引数を2つとるand・or・xorの4つがあります。今回はunsigned int32で行ってみましょう。

.assembly hina{}

.method public static void main(){
    .entrypoint
    .maxstack 2
    
    ldc.i4 0xFEDCBA98 //1111 1110 1101 1100 1011 1010 1001 1000
    ldc.i4 0x12345678 //0001 0010 0011 0100 0101 0110 0111 1000
    and
    call void [mscorlib]System.Console::WriteLine(unsigned int32)
    //0x12141218        0001 0010 0001 0100 0001 0010 0001 1000
    
    ldc.i4 0xFEDCBA98 //1111 1110 1101 1100 1011 1010 1001 1000
    ldc.i4 0x12345678 //0001 0010 0011 0100 0101 0110 0111 1000
    or
    call void [mscorlib]System.Console::WriteLine(unsigned int32)
    //0xFEFCFEF8        1111 1110 1111 1100 1111 1110 1111 1000
    
    ldc.i4 0xFEDCBA98 //1111 1110 1101 1100 1011 1010 1001 1000
    ldc.i4 0x12345678 //0001 0010 0011 0100 0101 0110 0111 1000
    xor
    call void [mscorlib]System.Console::WriteLine(unsigned int32)
    //0xECE8ECE0        1110 1100 1110 1000 1110 1100 1110 0000
    
    ret
}

それぞれ、2つの引数をとります。「and」はビットごとの論理積、「or」はビットごとの論理和、「xor」はビットごとの排他的論理和になります。

実行結果は下のようになります。

I:\temp\il>11 符号無し版
303305240
4277993208
3974687968

I:\temp\il>11-2 符号付き版
303305240
-16974088
-320279328

シフト演算

シフト演算は、算術シフト演算と、論理シフト演算があります。この2つはさらに右シフトと、左シフトの2つに分けられます。論理シフト演算はシフトして空いた場所に0を詰めます。算術シフト演算の左シフトは論理シフトと同じく0を詰めるだけです。右シフト演算は論理シフトと違い、一番左のビットで空いたところを埋めます。

つまり、左シフトはshl(shift integer left)一つの命令しかありません。そして右シフトは論理演算としてshr(shift integer right)、算術としてshr.un(shift integer right, unsigned)が用意されています。

ちなみ、最初にプッシュされた方がシフトされる側、後にプッシュされた方がシフトする側の数になります。

.assembly hina{}

.method public static void main(){
    .entrypoint
    .maxstack 2
    
    ldc.i4 1
    ldc.i4 5
    shl       //321
    call void [mscorlib]System.Console::WriteLine( int32)
    
    ldc.i4 -1024 // 0xFFFFFC00    1111 1111 1111 1111 1111 1100 0000 0000
    ldc.i4 5
    shr       //-32 0xFFFFFFE0   1111 1111 1111 1111 1111 1111 1110 0000
    call void [mscorlib]System.Console::WriteLine( int32)
    
    ldc.i4 -1024
    ldc.i4 5
    shr.un    //134217696 0x7FFFFE0  0000 0111 1111 1111 1111 1111 1110 0000
    call void [mscorlib]System.Console::WriteLine( int32)
    
    ret
}

「shl.un」という命令は存在しないので注意しましょう。

符号なし除算余り算

「add,sub,mul」と違い割り算では符号のあるなしが大きく関わります(addとsubは符号有り無しどちらでも演算方法が変わらず、mulは符号で意味が違うようになる時にはオーバーフローしてしまうため)。そのため、div.unrem.unという命令が用意されています。

.assembly hina{}

.method public static void main(){
    .entrypoint
    .maxstack 2
    
    ldc.i4 -2000000000
    ldc.i4 2
    div
    call void [mscorlib]System.Console::WriteLine(int32)
    
    
    ldc.i4 -2000000000
    ldc.i4 2
    div
    call void [mscorlib]System.Console::WriteLine(unsigned int32)
    
    ldc.i4 -2000000000
    ldc.i4 2
    div.un
    call void [mscorlib]System.Console::WriteLine(int32)
    
    
    ldc.i4 -2000000000
    ldc.i4 2
    div.un
    call void [mscorlib]System.Console::WriteLine(unsigned int32)
    
    ret
}

実行結果は下のようになります。

I:\temp\il>11
-1000000000
3294967296
1147483648
1147483648

remは省略です。



場所を占領するのでint64は利用しませんでした。試しに利用してみるのも良いと思います。


ページの一番上へ
前のページへ 一覧に戻る 次のページへ
初版2006-11-19
[Atelier Blue アトリエブルー]Homeプログラミング IL(CIL,MSIL)>論理演算・シフト演算・符号なし除算余り算