カテゴリー
Java

Java(Step7-2)

メソッド

整数の内部

値はビットとして表現されます。ここでは、整数の内部のビットを扱う演算子を説明していきます。

ビット単位の論理演算

論理演算は、論理型でなく、整数型に対しても適用できます。整数型オペランドに論理演算子を適用すると、ビット単位の論理演算が行われます。整数型に対して適用できるビット単位の論理演算子をまとめたのが以下の表です。

x & yx と y のビット単位の論理積を生成。
x | yx と y のビット単位の論理和を生成。
x ^ yx と y のビット単位の排他的論理和を生成。
~xx のビット単位の補数を生成。
ビット単位の論理演算子

&ビット論理積演算子(bitwise and operator)、|ビット論理和演算子(bitwise inclusive or operator)、^ビット排他的論理和演算子(bitwise exclusive or operator)、~ビット単位の補数演算子(bitwise complement operator)と呼ばれます。これらの演算子で行われる論理演算の真理値表が以下になります。

ビット単位の論理演算の真理値表

2つの整数を読み込んで、ビット単位の論理演算を行った結果を表示するプログラムを以下に示します。

//BitwiseOperation.java
//int型整数のビット単位の論理積・論理和・排他的論理和・補数を表示
import java.util.Scanner;

public class BitwiseOperation {
    //int型のビット構成を表示
    static void printBits(int x){
        for(int i = 31; i >= 0; i--)
            System.out.print(((x >>> i & 1) == 1) ? '1' : '0');
    }
    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);

        System.out.println("2つの整数を入力してください。");
        System.out.print("a:"); int a = stdIn.nextInt();
        System.out.print("b:"); int b = stdIn.nextInt();

        System.out.print("a     = "); printBits(a);
        System.out.print("\nb     = "); printBits(b);
        System.out.print("\na & b = "); printBits(a & b);
        System.out.print("\na | b = "); printBits(a | b);
        System.out.print("\na ^ b = "); printBits(a ^ b);
        System.out.print("\n~a    = "); printBits(~a);
        System.out.print("\n~b    = "); printBits(~b);
        stdIn.close();
    }

}
BitwiseOperation.java実行結果

シフト演算

メソッド printBits に初めて登場する演算子があります。>>>演算子(>>> operator)です。この演算子と<<演算子(<< 演算子)と>>演算子(>> 演算子)は、整数中のビットを左または右にシフトした値を生成する演算になります。これらの演算子をまとめて、シフト演算子(shift operator)と呼びます。その働きを以下のプログラムで示します。

//ShiftOperation.java
//int型の値を左右にシフトした値を表示
import java.util.Scanner;

public class ShiftOperation {
    //int型のビット構成を表示
    static void printBits(int x){
        for(int i = 31; i >= 0; i--)
            System.out.print(((x >>> i & 1) == 1) ? '1' : '0');
    }

    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);

        System.out.print("整数:"); int x = stdIn.nextInt();
        System.out.print("シフトするビット数:"); int n = stdIn.nextInt();

        System.out.print("整数    = "); printBits(x);
        System.out.print("\nx <<  n = "); printBits(x << n);
        System.out.print("\nx >>  n = "); printBits(x >> n);
        System.out.print("\nx >>> n = "); printBits(x >>> n);
        stdIn.close();
    }
}
ShiftOperation.java実行結果
  • x << n …左シフト

xをnビット左にシフトして、空いたビットに0を詰めた値を生成します。シフトの結果は x × 2のn乗となります。

  • x >> n …右シフト

右方向への算術シフト(arithmetic shift)を行います。最上位の符号ビット以外のビットをシフトし、空いたビットをシフト前の符号ビットで埋め尽くした値を生成します。

また、1ビット左にシフトすると値が2倍になり、1ビット右にシフトすると値が2分の1になる関係性が保たれます。xが非負の値を持つと、x + 2のn乗の商の整数部がシフト結果になります。

  • x >>> n …右シフト

右方向への論理シフト(logical shift)を行います。符号ビットを特別に考慮することなく、まるごとnビットシフトした値を生成します。xが負の値であれば、符号ビットが1から0に変わるため、演算によって得られる結果は正の値になります。

ビット数のカウント

int型の整数を構成する32個のビットの中に”1″であるビットが何個あるかをカウントするプログラムを作りましょう。

//CountBits.java
//int型整数中の1であるビット数をカウント
import java.util.Scanner;

public class CountBits {
    //int型のビット構成を表示
    static void printBits(int x){
        for(int i = 31; i >= 0; i--)
            System.out.print(((x >>> i & 1) == 1) ? '1' : '0');
    }
    //int型整数中の1であるビット数をカウント
    static int countBits(int x){
        int bits = 0;
        while (x != 0){
            if((x & 1) == 1) bits++;
            x >>>= 1;
        }
        return bits;
    }

    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);

        System.out.print("整数:");
        int x = stdIn.nextInt();

        System.out.print("ビット構成 = ");
        printBits(x);
        System.out.println("\n1であるビット数 = " + countBits(x));
    }
}
CountBits.java実行結果

メソッド countBits は、仮引数xに受け取った整数中に存在する”1″であるビットの個数をカウントして、その値を返すメソッドです。

  1. xと1の論理積が1となるかどうかによって、xの最下位ビットの値を調べます。その結果が1であれば、xの最下位ビットは1になるので、bitsをインクリメントします。
  2. 全ビットを右に1ビット論理シフトします。その結果、調べ終わった最下位ビットがはじき出されます。