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

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

この記事を読むのに必要な時間:およそ 3 分

解説: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

今回のまとめ

  • コンピュータ内部では,全てが2進数で表現されている。2進数は桁数が多くなるため,16 進数に変換して表示する。
  • 4桁の2進数と1桁の16進数は1対1に対応するので,対応する10進数の値とともに暗記しておこう。
  • 整数型と実数型では,同じ数値を代入しても全く異なるビット列となる。

基数さまざま

コンピュータというと2進数・16進数ばかりに目がいってしまいます。コンピュータのハードウエア,ソフトウエアに限ってい言えば,基数が異なる数といえばこのぐらい知っておけばいいからです。

ところが,実は私たちは日常的に,その他の異なる基数を用いているんです。⁠そんなばかな? 10進数しか使ってないぞ?」と思うでしょう。では,ちょっと時計を見てください。アナログ時計がいいですね。文字盤は1から始まって12まで。これは12進数ですね。時計の短針が一周すると半日。時計の短針が2周して一日。一日を基準にすると24進数です。24進むごとに位が変わる(日付が変わる)のです。

同様に60秒で1分,60分で1時間。ひと月はほぼ31日でひと月,干支は12d で一回り。角度の単位は360度。考えてみるといろいろあるものです。

古代シュメルの人々は60進数を用いていたそうです。ずいぶん大きな数が扱えそうですね。どんな風にカウントしていたのか,知りたいものです。どんな必要からこんなに大きな基数になったのでしょう。不思議ですね。

著者プロフィール

平田敦(ひらたあつし)

地方都市の公立工業高等学校教諭。趣味はプログラミングと日本の端っこ踏破旅行。2010年のLotYはRuby。結城浩氏のような仕事をしたいと妄想する30代後半♂。