[Java] ビット演算子

AND, OR, XOR, NOT, 左シフト、右シフトの使い方

出力用のクラスを準備

package net.fernwelt;

public class P {
  // 2進数文字列 を int へ変換
  public static int bd(String bin) {
    return Integer.parseInt(bin, 2);
  }

  // int を 2進数文字列 へ変換して出力
  public static void b(int n) {
    String r = Integer.toBinaryString(n).toUpperCase();
    System.out.println(r);
  }

  // 上にほぼ同じ。32文字になるまで左端を0で埋める。
  public static void bi(int n) {
    String r = Integer.toBinaryString(n).toUpperCase();
    if(r.length() < 32){
      int l = 32 - r.length();
      for (int i = 0; i < l; i++) {
        r = 0 + r;
      }
    }
    System.out.println(r);
  }

  // int を 16進数文字列 へ変換して出力
  public static void h(int n) {
    String r = Integer.toHexString(n).toUpperCase();
    System.out.println(r);
  }

  // 上にほぼ同じ。8文字になるまで左端を0で埋める。
  public static void hi(int n) {
    String r = Integer.toHexString(n).toUpperCase();
    if(r.length() < 8){
      int l = 8 - r.length();
      for (int i = 0; i < l; i++) {
        r = 0 + r;
      }
    }
    System.out.println(r);
  }

  private P() {
  }
}

& - and演算

ビットごとにアンド演算を行う。非短絡論理積演算子と同じ文字の演算子。

&演算によりどこのビットが立っているかを判別したり、特定の位置のバイナリ文字列を取り出すことができる。

ということで実際にコードを書いてみる。

package jp.fernweh;

import net.fernwelt.P;

public class And {
  public static void main(String[] args) {
    P.b(P.bd("1111") & P.bd("1100"));
    P.b(P.bd("1100") & P.bd("1010"));
    P.b(P.bd("1100") & P.bd("0011"));
    P.b(P.bd("00001111") & P.bd("01010101"));

    System.out.println();

    P.h(0xFFFF & 0xFFFF);
    P.h(0xFF00 & 0xF0F0);
    P.h(0xFFFF & 0xABCD);
    P.h(0x1234 & 0x9876);
  }
}

結果

1100
1000
0
101

FFFF
F000
ABCD
1034

| - or演算

ビットごとに 論理和演算 を行う。非短絡論理和演算子と同じ文字。

どちらかのビットが立っていれば1になる。

package jp.fernweh;

import net.fernwelt.P;

public class Or {
  public static void main(String[] args) {

    P.b(P.bd("1111") | P.bd("1001"));
    P.b(P.bd("0000") | P.bd("1001"));
    P.b(P.bd("00001111") | P.bd("01010101"));

    System.out.println();
    P.h(0xFFFF | 0x0000);
    P.h(0x4321 | 0x1234);
    int n1 = 0xFF00, n2 = 0x1234;
    P.h(n1 | n2);
    P.h(n1 & n2);
    P.h((n1 | n2) & (n1 & n2));
    P.h((n1 | n2) | (n1 & n2));
  }

}

結果

1111
1001
1011111

FFFF
5335
FF34
1200
1200
FF34

^ - xor演算

ビットごとに排他的論理和演算を行う。

package jp.fernweh;

import net.fernwelt.P;

public class Xor {
  public static void main(String[] args) {
    P.b(P.bd("1111") ^ P.bd("0000"));
    P.b(P.bd("1111") ^ P.bd("1100"));
    P.b(P.bd("00001111") ^ P.bd("01010101"));

    System.out.println();

    P.h( 0xABCD ^ 0xABCD);
    P.h( 0xABCD ^ 0x0000);
    P.h( 0xABCD ^ 0xFFFF);
    P.h( (0xABCD ^ 0x0000) + (0xABCD ^ 0xFFFF));
    P.h( (0xABCD ^ 0x0000) | (0xABCD ^ 0xFFFF));

    System.out.println();

    int r1 = (int) (Math.random() * 0xFF);
    int r2 = (int) (Math.random() * 0xFF);
    System.out.println((r1 ^ r2 ^ r2) == r1);
    System.out.println((r1 ^ r2 ^ r1 ^ r2 ^ r1) == r1);
    System.out.println((r1 ^ r2 ^ r2 ^ r2 ^ r1 ^ r1 ^ r2) == r1);
  }
}

結果

1111
11
1011010

0
ABCD
5432
FFFF
FFFF

true
true
true

~ - not演算

ビットごとにノット演算を行う。

package jp.fernweh;

import net.fernwelt.P;

public class Not {
  public static void main(String[] args) {

    P.b(~P.bd("11110000"));
    P.b((byte) ~P.bd("11110000"));

    System.out.println();

    P.h(~0x76543210);

    System.out.println();

    int r = (int) (Math.random() * 0xFFFF);
    System.out.println(r + ~r);
    System.out.println(r + ~r == 0xFFFFFFFF);
    System.out.println( -r == (~r + 1) );
    System.out.println( ~r == - r - 1 );
    System.out.println((r + ~r) == (~(r + ~r + 1)));
    System.out.println((~r) == (r ^ -1));
  }

}

結果

11111111111111111111111100001111
1111

89ABCDEF

-1
true
true
true
true
true
true

<< - 左シフト

ビット列を指定した数値だけ左へスライドする。int 型で演算が行われるため 31ビットシフトまでしかできない。32ビットシフトしようとしても0ビットシフト?と同様になる( 0 を指定してもエラーになったりはしない)

1ビット左シフトにより、数値が2倍になる。

package jp.fernweh;

import net.fernwelt.net;

public class LeftShift {
  public static void main(String[] args) {
    for(short b = (short) 0xFFFF; b != 0; b = (short)(b << 1) ){
      P.b(b);
    }

    System.out.println();

    for(int i = 0,n = 0xFFFFFFFF; n != 0; i++, n = n << i ) {
      P.b(n);
    }
  }

}

結果

11111111111111111111111111111111
11111111111111111111111111111110
11111111111111111111111111111100
11111111111111111111111111111000
11111111111111111111111111110000
11111111111111111111111111100000
11111111111111111111111111000000
11111111111111111111111110000000
11111111111111111111111100000000
11111111111111111111111000000000
11111111111111111111110000000000
11111111111111111111100000000000
11111111111111111111000000000000
11111111111111111110000000000000
11111111111111111100000000000000
11111111111111111000000000000000

11111111111111111111111111111111
11111111111111111111111111111110
11111111111111111111111111111000
11111111111111111111111111000000
11111111111111111111110000000000
11111111111111111000000000000000
11111111111000000000000000000000
11110000000000000000000000000000
package jp.fernweh;

import net.fernwelt.net;

public class LeftShifter {
  public static void main(String[] args) {
    for (int i = 0, n = 10, p = 10; n != 0; i++, p = n,n = n << i) {
      System.out.println("[ "+p + " << "+i +" ]");

      System.out.print("bin : ");
      P.b(n);

      System.out.print("hex : ");
      P.h(n);

      System.out.print("dec : ");
      System.out.println(n);
      System.out.println();
    }
  }
}

結果

[ 10 << 0 ]
bin : 1010
hex : A
dec : 10

[ 10 << 1 ]
bin : 10100
hex : 14
dec : 20

[ 20 << 2 ]
bin : 1010000
hex : 50
dec : 80

[ 80 << 3 ]
bin : 1010000000
hex : 280
dec : 640

[ 640 << 4 ]
bin : 10100000000000
hex : 2800
dec : 10240

[ 10240 << 5 ]
bin : 1010000000000000000
hex : 50000
dec : 327680

[ 327680 << 6 ]
bin : 1010000000000000000000000
hex : 1400000
dec : 20971520

[ 20971520 << 7 ]
bin : 10100000000000000000000000000000
hex : A0000000
dec : -1610612736

>> - 右シフト(算術シフト、符号拡張シフト)

  • ビット列を右へスライドする
  • 符号が変わらないように左端のビットは埋められる
  • 数値が1/2倍になる

>>> - 右シフト(論理シフト、ゼロ拡張シフト)

算術シフトと違って左端に補われる数値は 0 。したがって、論理シフトを行うとマイナスの値は必ずプラスになる。

package jp.fernweh;

import net.fernwelt.net;

public class RightShift {

  public static void main(String[] args) {
    for (
      int i = 0, n = 1 << 31, p = 1 << 31;
      n != 0;
      i++, p = n, n = n >> i
    ) {
      System.out.println("[ " + p + " << " + i + " ]");

      System.out.print("bin : ");
      P.bi(n);

      System.out.print("hex : ");
      P.hi(n);

      System.out.print("dec : ");
      System.out.println(n);
      System.out.println();
    }
  }
}

結果

[ -2147483648 << 0 ]
bin : 10000000000000000000000000000000
hex : 80000000
dec : -2147483648

[ -2147483648 << 1 ]
bin : 11000000000000000000000000000000
hex : C0000000
dec : -1073741824

[ -1073741824 << 2 ]
bin : 11110000000000000000000000000000
hex : F0000000
dec : -268435456

[ -268435456 << 3 ]
bin : 11111110000000000000000000000000
hex : FE000000
dec : -33554432

[ -33554432 << 4 ]
bin : 11111111111000000000000000000000
hex : FFE00000
dec : -2097152

[ -2097152 << 5 ]
bin : 11111111111111110000000000000000
hex : FFFF0000
dec : -65536

[ -65536 << 6 ]
bin : 11111111111111111111110000000000
hex : FFFFFC00
dec : -1024

[ -1024 << 7 ]
bin : 11111111111111111111111111111000
hex : FFFFFFF8
dec : -8
package jp.fernweh;

import net.fernwelt.net;

public class RightShift {

  public static void main(String[] args) {
    for (
      int i = 0, n = -1 >>> 1, p = -1 >>> 1;
      n != 0;
      i++, p = n, n = n >> i
    ) {
      System.out.println("[ " + p + " << " + i + " ]");

      System.out.print("bin : ");
      P.bi(n);

      System.out.print("hex : ");
      P.hi(n);

      System.out.print("dec : ");
      System.out.println(n);
      System.out.println();
    }
  }
}

結果

[ 2147483647 >> 0 ]
bin : 01111111111111111111111111111111
hex : 7FFFFFFF
dec : 2147483647

[ 2147483647 >> 1 ]
bin : 00111111111111111111111111111111
hex : 3FFFFFFF
dec : 1073741823

[ 1073741823 >> 2 ]
bin : 00001111111111111111111111111111
hex : 0FFFFFFF
dec : 268435455

[ 268435455 >> 3 ]
bin : 00000001111111111111111111111111
hex : 01FFFFFF
dec : 33554431

[ 33554431 >> 4 ]
bin : 00000000000111111111111111111111
hex : 001FFFFF
dec : 2097151

[ 2097151 >> 5 ]
bin : 00000000000000001111111111111111
hex : 0000FFFF
dec : 65535

[ 65535 >> 6 ]
bin : 00000000000000000000001111111111
hex : 000003FF
dec : 1023

[ 1023 >> 7 ]
bin : 00000000000000000000000000000111
hex : 00000007
dec : 7
package jp.fernweh;

import net.fernwelt.net;

public class RightShifter {
  public static void main(String[] args) {
    for (
      int i = 0, n = -1 >> 1, p = -1 >> 1;
      n != 0;
      i++, p = n, n = n >>> i
    ) {
      System.out.println("[ " + p + " << " + i + " ]");

      System.out.print("bin : ");
      P.bi(n);

      System.out.print("hex : ");
      P.hi(n);

      System.out.print("dec : ");
      System.out.println(n);
      System.out.println();
    }
  }
}

結果

[ -1 >>> 0 ]
bin : 11111111111111111111111111111111
hex : FFFFFFFF
dec : -1

[ -1 >>> 1 ]
bin : 01111111111111111111111111111111
hex : 7FFFFFFF
dec : 2147483647

[ 2147483647 >>> 2 ]
bin : 00011111111111111111111111111111
hex : 1FFFFFFF
dec : 536870911

[ 536870911 >>> 3 ]
bin : 00000011111111111111111111111111
hex : 03FFFFFF
dec : 67108863

[ 67108863 >>> 4 ]
bin : 00000000001111111111111111111111
hex : 003FFFFF
dec : 4194303

[ 4194303 >>> 5 ]
bin : 00000000000000011111111111111111
hex : 0001FFFF
dec : 131071

[ 131071 >>> 6 ]
bin : 00000000000000000000011111111111
hex : 000007FF
dec : 2047

[ 2047 >>> 7 ]
bin : 00000000000000000000000000001111
hex : 0000000F
dec : 15
Share
関連記事