はじめMath! Javaでコンピュータ数学

第7回同じ値でも中身はいろいろ[後編]

前回は2進数・10進数・16進数の相互変換方法を学びました。今回はコンピュータ内の変数に、数値がどのように格納されているか表示させるプログラムを作りましょう。あわせて筆算で変換を行い、プログラムの実行結果と一致するかを確かめましょう。

問題:int型、long型、float型、double型に格納された数値を16 進数形式で表示してみましょう。

同じ数値が、違う型の変数に格納されると、ビット列にどのような違いが生じるかを実験して確かめよう。

(1) int型、long型の仕様について調査しましょう(実数型については後々学びますので、float型やdouble型の仕様についての調査を省きます⁠⁠。

(2) 目的の処理をするために必要な命令群について調べましょう。

(3) 整数値(1,-1,85,-85)を入力し、それを16進数表示できるソースコードを作りましょう。確認のために、入力する整数値を筆算で16進数に変換しておきましょう。

課題解決の結果作成されるコードは十人十色でしょう。解説編に掲載するソースコードは私というフィルタを通して作られた一例でしかありません。それぞれが掘り当てた資料や組み上げたコードこそがその人の資産となります。調査・実験に費やす時間を大切にしましょう。

解説:int 型、long 型、float 型、double型に格納された数値を16 進数形式で表示してみましょう。

(1)int 型、long 型の仕様について調査しましょう。

整数型はビット数の違いをのぞけば、同様に最左が符号ビット、残りが数値を表しています。負の数は2の補数で表現されています。int型の桁数は32ビット、long型の桁数は64ビットです。どちらも2進数で表現するにはあまりに長く、一目で値を理解するのは大変です。16進数ならばビット数を4で割っただけの桁数になりますから、ずいぶん読み取りやすくなります。それで、メモリ内容を表示する場合には16進数が用いられるのです。

(2)目的の処理をするために必要な命令群について調べましょう。

Java言語の用意しているプリミティブ数値型のラッパークラスには、"parse***"といった名称のメソッドがあります。これらは文字列形式で引数に指定された数値を"***" で指定した型に変換してくれます。

例えば、ソースコードShowHexCode.javaの14行目は文字列変数inputtextの内容をint型に変換します。

20行目のtoHexStringというメソッドは、そのクラスに格納されている整数値を表す16進数の文字列を返します。その他ShowHexCode.javaで使用しているラッパークラスの各種メソッドの詳細は、ヒントで紹介したJava言語のAPIリファレンスサイトを参照して確認してください。

(3)整数値(1,-1,85,-85)を入力し、それを16進数表示できるソースコードを作りましょう。確認のために、入力する整数値を筆算で16 進数に変換しておきましょう。

(1)D,(-1)D は本文中で既に変換例を示したのでここでは省略します。(85)D,(-85)D の変換手順は次の通りです。

画像

これをint型に格納すると(0x0000 0055)Hなのですが、左側の連続する0は見た目に邪魔で理解を妨げるので、int型に格納したとしても(0x55)Hと書きます。

この結果を用いて(-85)D も16 進数に変換しましょう。

画像

さて、以上の調査から今回の課題の解決策として、次のようなコードを提案します。

リスト6.1 ShowHexCode.java
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
//filename : ShowHexCode.java
import java.io.*;
class ShowHexCode {
  public static void main(String[] args)
                                throws IOException {

    System.out.print("10 進整数値を入力して下さい。>");

    BufferedReader br = new BufferedReader(
                               new InputStreamReader(System.in)
                             );

    String inputtext = br.readLine();
    int num = Integer.parseInt(inputtext);
    long numl = Long.parseLong(inputtext);
    float numf = Float.parseFloat(inputtext);
    double numd = Double.parseDouble(inputtext);

    System.out.println("[int](0x"
       + Integer.toHexString(num) + ")H");
    System.out.println("[long](0x"
       + Long.toHexString(numl) + ")H");
    System.out.println("[float](0x"
       + Integer.toHexString(Float.floatToIntBits(numf))
       + ")H ");
    System.out.println("[double](0x"
       + Long.toHexString(Double.doubleToRawLongBits(numd))
       + ")H");
  }// end of main
}// end of class

このコードは、入力された数値が10進数で整数値の場合には正しく処理します。実数値(小数点を含む数値)は処理できません。2進数や16進数も入力として受け付けません。エラーを発生してプログラムが強制終了します。

入出力部分は例外処理命令で囲むのが常套手段ですが、ソースコードをできるだけ短くしたいので、メインメソッド冒頭(4,5行目)で例外処理宣言を記述しました。例外が発生すると、メッセージを表示してプログラムは強制終了します。最低でもこうしておかないと、Java言語の実行環境は実行を許可しません。

さて、入力した数値は筆算した通りの出力となったでしょうか。

課題がこなせたら、思い思いの値を入力して筆算の結果と比較してみると良いでしょう。例えば、(-3)D,(-2)D,(-1)D,(0)D,(1)D,(2)D,(3)D といった連続した値がどう表されているかを確認するのは有益な作業です。

また、それぞれの変数の許容範囲外の数値を入力し、出力結果を確かめてみるのも興味深い演習となります。

それでは以下に実行結果を示します。(1)D や(85)D を入力したときの出力結果のうち、int型やlong型の桁数が少ないのは、ビット列左端から連続するゼロの桁の表示を意図的に省いているためです。

整数型と実数型の出力結果はまるで違いますね。どうしてこんなにも違うのでしょうか。実数型の仕組みについては次回学習します。意外とシンプルですよ。お楽しみに。

リスト6.1 ShowHexCode.java の実行結果
10 進整数値を入力して下さい。> 1
[int](0x1)H
[long](0x1)H
[float](0x3f800000)H
[double](0x3ff0000000000000)H
10 進整数値を入力して下さい。> -1
[int](0xffffffff)H
[long](0xffffffffffffffff)H
[float](0xbf800000)H
[double](0xbff0000000000000)H
10 進整数値を入力して下さい。> 85
[int](0x55)H
[long](0x55)H
[float](0x42aa0000)H
[double](0x4055400000000000)H
10 進整数値を入力して下さい。> -85
[int](0xffffffab)H
[long](0xffffffffffffffab)H
[float](0xc2aa0000)H
[double](0xc055400000000000)H

おすすめ記事

記事・ニュース一覧