Javaに関する様々な情報をご紹介します。

4シフト演算子

Javaに関する様々な情報をご紹介します。

シフト演算子

このページでは、Javaで用意されている<<>>などのシフト演算子について説明します。

概要

シフト演算子には以下の演算子が用意されています。シフト演算子は整数型の値に使用されます。

演算子 記入例 説明
<< x << y xのビットをyビットだけ、左にシフトさせる。右端には0を埋める。
>> x >> y xのビットをyビットだけ、右にシフトさせる。左端にはその時の最上位ビットと同じ符号を埋める。
>>> x >>> y xのビットをyビットだけ、右にシフトさせる。左端には0を埋める。

<<の説明

<<は左オペランドのビットを右オペランドのビット分だけ、左にシフトさせます。左へのシフトは元の値に2をシフト分累乗した値を乗算することを意味します。

2 << 3 (10進数の2を3ビット左にシフト)

2 << 3 (10進数の2を3ビット左にシフト)

>>の説明

>>は左オペランドのビットを右オペランドのビット分だけ、右にシフトさせます。右へのシフトは元の値に2をシフト分累乗した値を除算することを意味します。左端には最上位のビットと同じ符号が入ります。最上位のビットと同じ符号が入る理由は2の補数表現において、負数の最上位ビットは1であると言うところからきています。最上位ビットが1である10進数-4を右にシフトさせた場合、左端に0が入っては正確な演算結果が得られません。

-4 >> 2 (10進数の-4を2ビット右にシフト)

-4 >> 2 (10進数の-4を2ビット右にシフト)

>>>の説明

>>>は左オペランドのビットを右オペランドのビット分だけ、右にシフトさせます。左端には0が入ります。左端に0が入ると言うことは >>>は演算結果に正負の区別を持たないとも言えます。>>>演算子は符号の区別を持たない演算処理に使用します。

128 >>> 4 (10進数の128を4ビット右にシフト)

128 >>> 4 (10進数の128を4ビット右にシフト)

【例1】上記のイラストで示したシフト演算処理を例示します。

public class ExOperator9 {
    public static void main(String[] args) {
        int x1 = 2;
        int x2 = -4;
        int x3 = 128;
        System.out.println("x1は" + (x1 << 3));   //(1)
        System.out.println("x2は" + (x2 >> 2));   //(2)
        System.out.println("x3は" + (x3 >>> 4));   //(3)
    }
}

解説1

  1. (1)変数x1を左に3ビットシフトさせた値を表示します。
  2. (2)変数x2を右に2ビットシフトさせた値を表示します。
  3. (3)変数x3を右に4ビットシフトさせた値を表示します。

実行結果1

D:\JAVA>javac ExOperator9.java

D:\JAVA>java ExOperator9
x1は16
x2は-1
x3は8

D:\JAVA>

データの溢れ

シフト演算結果が演算元(左オペランド)のデータ型に収まり切れない時、演算結果は想定していたものと異なる値になります。演算元のデータ型より溢れたデータは削除され、残りのデータ型内のデータが演算結果と見なされます。

int型を使用する場合

演算元のデータにint型を使用し、演算結果の値がint型に収まりきれないことが想定される場合、シフト演算処理は以下のように行われます。

2000000000 << 2 (10進数の2000000000を2ビット左にシフト)

2000000000 << 2 (10進数の2000000000を2ビット左にシフト)

char型、byte型、short型を使用する場合

char型、byte型、short型のデータは算術演算を行う時、int型に変換されて演算が行われます。その特性のため、シフト演算の結果、想定していたものとは異なる値が生成される場合があります。シフト演算においてはint型、データ容量が多い場合はlong型を使うようにします。

-8 >>> 2 (10進数の-8を2ビット右にシフト)

-8 >>> 2 (10進数の-8を2ビット右にシフト)

【例2】上記のイラストで示したシフト演算処理を例示します。

public class ExOperator10 {
    public static void main(String[] args) {
        int x1 = 2000000000;
        byte x2 = -8;
        System.out.println("x1は" + (x1 << 2));   //①
        System.out.println("x2は" + (x2 >>> 2));   //②
    }
}

解説2

  1. (1)変数x1を左に2ビットシフトさせた値を表示します。
  2. (2)変数x2を右に2ビットシフトさせた値を表示します。

実行結果2

D:\JAVA>javac ExOperator10.java

D:\JAVA>java ExOperator10
x1は-589934592
x2は1073741822

D:\JAVA>

剰余還元

シフト演算を行う際、右オペランドには左オペランドのデータ型のビット数を超える値を設定すべきではありません。つまり、左オペランドがint型の場合右オペランドは31以下、左オペランドがlong型の場合右オペランドは63以下にすべきです。

右オペランドに左オペランドのビット数を超える数を設定した場合は、左オペランドがint型の場合は右オペランドの下位5ビットが、左オペランドがlong 型の場合は右オペランドの下位6ビットがシフト演算に適用されます。そのため、演算結果は想定していたものと異なる値が算出されます。この法則は指定された値がビット幅を元とする剰余系に還元されると言われます。

4シフト演算子