Home >> Lecture 4


第4回 データ入力と条件分岐(5/1)


4−1.値の入力

標準のJavaのライブラリでは、ターミナルに表示するだけで、ターミナルからユーザにデータの値を 入力してもらうのは結構大変です。そのため、タートル・グラフィックスのライブラリでは、そのようなメソッドを 各データ型に対して用意しました。ここでは、実数に関しては、省略します。

■ターミナル(コンソール)からの文字列、整数、長桁整数入力

ターミナルから入力をして変数に代入してくれるメソッドとして、以下のようなものが使えます。

 inputString( )  …文字列の入力
 inputInteger( )  …整数の入力
 inputLongInteger( )  …長桁整数の入力

プログラム上では、値を返してくれる為に、変数に対して代入文を用いて、= の右側にこれらのメソッドを記述して行きます。 プログラム実行時には、それぞれのメソッドが呼ばれた際に、ユーザがデータを入力する必要がありますが、 値を入力した後は、最後にターミナルでReturn(Enter)キーを押します。 以下のプログラムの断片は、startメソッドの中だけを記述しています。


	printLine( "Please input a text." );
	String  s = inputString( );					// sに1行入力してくれます。ただし改行コードは入力されません。
	print( "Please input a integer: " );
	int x = inputInteger( );		//  xに整数を入力してくれます
	print( "Please input a long integer: " );
	long xx = inputLongInteger( );		// xxに長桁整数を入力してくれます
		

★実習4-1 ターミナルからのユーザの入力を鸚鵡(おうむ)返しに表示するプログラムを作る

上記のプログラムの断片を用いて、整数、長桁整数、文字列をターミナルから入力してもらい、それを 最後にそのまま出力するプログラムを作成しなさい。クラス名はPractice0401とします。

■ダイアログを用いた表示と入力

タートル・グラフィックスでは文字列をダイアログで表示するためには、既にご紹介したようにdisplayDialogメソッドが 用意されています。これはターミナルに表示を行なうprintLineやprintと異なり、文字列しか表示することができませんので、 文字列の形にデータを変換する必要があります。

 displayDialog( 文字列 )

文字列以外のデータ値を表示させる為には、空の文字列と足し算をする必要があります。


	displayDialog( "ダイアログに表示するテキスト" );	// 文字列をそのまま表示する場合
	displayDialog( "" + 938437 );					// 整数を表示する場合
	displayDialog( "" + 93248230902L );			// 長桁整数を表示する場合
		

また、メッセージを出してダイアログからデータをユーザに入力してもらうために、文字列、整数、長桁整数用のメソッドが それぞれ用意されています。

  displayInputDialog( 文字列, 省略時の文字列 )  …文字列の入力
  displayInputIntegerDialog( 文字列, 省略時の整数値 )  …整数の入力
  displayInputLongIntegerDialog( 文字列, 省略時の長桁整数値 )  …長桁整数の入力

これらのメソッドを呼び出して使うには、2つのパラメータと入力された値を受け取る変数が必要になります。 パラメータは、カンマ「,」で区切ります。 パラメータの1つめは、「メッセージとして表示される文字列」される文字列です。 パラメータの2つめは、「ユーザが何も入力しないときに使われる値(デフォルト値:Default Value)」です。 2つめのパラメータは入力フィールドに表示され、ユーザがそのままの状態で、 ただ単にOKボタンやReturn(Enter)キーを押したときに入力値と用いられます。

また、これらのダイアログの表示や入力を行なうすべてのメソッドでは、キャンセルボタンを用意してありますので、 そこでプログラムの実行を中止することができます。 以下のプログラムも、またもや、startメソッドの中だけを記述しています。


	String  inputText = displayInputDialog( "何か文字列を入力して下さい", "日曜日" );
	int   n = displayInputIntegerDialog( "Input integer value", 0 ); 
	long   m = displayInputLongIntegerDialog( "Input long integer value", 100000000L ); 
	displayDialog( "入力された文字列は" + inputText + "であり、整数は" + n + "であり、長桁整数は" + m + "です。" );
		

★実習4-1 ダイアログからのユーザの入力を鸚鵡(おうむ)返しに表示するプログラムを作る

上記のプログラムを記述し、コンパイルして実行してみなさい。クラス名はPractice0401とします。

★実習4-2 ダイアログから同時に2つの入力をもらうプログラムを作る

下記のプログラムは、ダイアログから月日を必ず4桁の整数で入力してもらい、上位2桁を月、 下位2桁を日として分解しています。またもや、startメソッドの中だけを記述しています。 実際にクラスを作成して、コンパイルして実行してみなさい。クラス名はPractice0402とします。


	int monthday = displayInputIntegerDialog( "4桁で月と日を入力してください", 1214 );
	int month = monthday / 100;		// 上位2桁を月として扱う
	int day = monthday % 100;		// 下位2桁を日として扱う
	displayDialog( "入力された月日は" + month + "月" + day + "日ですね。" );
		

4−2.データの型変換

■文字列と数と間の変換

★文字列と数字から構成される文字列、変数との違い

Javaでは、型を厳格に区別しますので、文字列の数字から構成される文字列と数字というのは、まったく扱いが違います。 また、名前も区別しますので、文字列で書かれた名前と、変数名は、まったく扱いが違います。


		"12345"		// Javaでは、これは数として解釈されません、数字から構成される文字列として解釈されます。
		12345		// Javaでは、これは整数の値として解釈されます。
		

このように数字から構成される文字列と整数は違いますので、注意して下さい。


		'x'		// Javaでは、単一文字のxとして解釈されます
		"x"		// Javaでは、文字列のxとして解釈されます
		x		// Javaでは、変数のxとして解釈され、式中に現れたら、それが保持する定数に置き換わります
		

このように文字、文字列と変数とは違います。次の出力の意味を理解してみて下さい。


		printLine( "x"+ x );
		

★文字列を整数に変換するためのメソッド

Javaでは、文字列から、整数あるいは実数に変換するためには、文字列の足し算や、強制的な型変換で行なうことはできません。 タートル・グラフィックスでは、そのためのメソッドが用意されています。

 convertToInteger( 文字列 )   … 数字の文字列を解釈し、整数の値に変換します
 convertToLongInteger( 文字列)   … 数字の文字列を解釈し、長桁整数の値に変換します
		
	convertToInteger(  "1234" )		// →  整数値の1234に変換されます
	convertToLongInteger( "3456" )		// → 長桁整数値の3456Lに変換されます
		

以下のプログラムは、startメソッドの中だけを記述しています。


	int x;
	String   s = displayInputDialog(  "Please input value for x", "0" );
	x = convertToInteger( s ); // 文字列を整数として解釈し変換しています
	long z = convertToLongInteger( s ); // 文字列を長桁整数として解釈し変換しています
		

さらに、タートル・グラフィックスのライブラリでは、基数を2つ目のパラメータとして与えることにより、 上記の2つのメソッドを用いて、16進数あるいは2進数(一般的にn進数)の整数や長桁整数で書かれた文字列を、 整数や長桁整数として解釈も出来ます。

  convertToInteger( 文字列, 基数 )   … 文字列を基数進数の数字として解釈し、整数の値に変換します
  convertToLongInteger( 文字列, 基数 )   … 文字列を基数進数の数字として解釈し、長桁整数の値に変換します
		
	convertToInteger(  "10010", 2 )		// →  2進数として解釈し、整数値の10010(10進数で18)に変換されます
	convertToInteger( "a53f", 16 )		// → 16進数として解釈し、整数値の0xa53f(10進数で42303)に変換されます
		

以下のプログラムも、またもや、startメソッドの中だけを記述しています。


	int x;
	print( "16進数を入力してください:" );
	String s = inputString( );
	x = convertToInteger( s, 16 );  // 16進数として解釈し整数に変換しています。
	long z = convertToLongInteger( s, 16 );   // 16進数として解釈し長桁整数に変換しています。
	printLine( "符号なし16進数"+ s + "を10進数に変換すると" + x + "になります。" );
		

★位取り法とn進数について

位取り法とは、数字の位置によって、桁が示される数の記述方法です。たとえば、542は、五百四十二を示します。 位取り法がなかった古代文明、メソポタミア、エジプト、それに続くギリシャ・ローマ、あるいは黄河文明は、 位を表すための記号が用いられていました。たとえば、漢数字の千二十一は、1×千+2×十+1を表しています。 千と十とがそれぞれ位を表すものです。たとえば、ローマ数字では、Iは1を、Vは5を、Xは10を、Lは50を、 Cは100を、Dは500を、Mは1000を表します。たとえば、位取り法で表記された、1876は、 次のように表さなければなりませんでした。


	1876→ローマ数字ではMDCCCLXXVI
		

数を位取り法で表すためには、「0」という記号が必要でした。千二十一は、1021 という形で、百を表す桁が0であることを示さなければなりません。 この「0」を用いた位取り法は、6〜7世紀頃のインドの数学で導入され、アラビア数字(現在我々が使っている 数字)に反映され、西洋に採り入れられたのは15世紀以降でした。それから、現在の我々が知っている 数学が発達します。

さて、紀元前後に栄えた古代マヤ文明は位取り法によって、記されていることがわかっています。 「0」を表す特殊な文字も用いられています。古代マヤ文明の天文学の正確さや、数の記述能力の正確さ、 合理的な暦の作られかたは目を見張るものがあります。なぜ、そこまで発達した文明であったかは、誰も 説明することができません。

位取り法を用いれば、10進数でも12進数でも2進数でも16進数でもすべて数の記述の仕方は同じです。 上位の(左に書かれる)桁は、基数倍された数を示しています。 この基数の表記が違うだけで、同じ整数を表すことには違いがありません。 たとえば、10進数では、5に対して、50は、10倍された50という数を示しています。 16進数では、4に対して、40は16倍された、10進数で表記するところの64という数を示しています。 2進数では、1に対して、10は、2倍された、10進数で表記するところの2という数を示しています。 n進数を10進数に変換したければ、基数を掛けていけば良いことになります。 たとえば、16進数の2a7は、次のように変換されます。 ちなみに16進数では、a=10, b=11, c=12, d=13, e=14, f=15を表します。


	2×16×16 + a(=10) × 16 + 7  → 512 + 160 + 7 → 679
		

逆に10進数表記された整数を、n進数表記するには、基数で割っていき、余りを取ります。 たとえば、10進数で表記された数を2進数で表記したい場合には、その数を基数の2で割っていき、 余りを求めます。たとえば、13にしましょう。0になるまで、2での整数除算を繰り返します。


	13÷2=6余り1、6÷2=3余り0、3÷2=1余り1、1÷2=0余り1
		

このときの余りだけを、反対方向から(この記述では、右から左へ)読んでいけば、「1101」で、 これが、10進数の13の2進数表記です。

ローマ数字は既にみたように、10進数と5進数をベースにしています。 古代メソポタミア文明(その一番最初はシュメール文明と呼ばれる)は、10進数と60進数をベースとしています。 古代エジプト文明は、基本的には10進数表記でしたが、シュメールもエジプトも、 角度に関しては、当初より現在と同じ360進数を使っていました。これもどうしてだか謎のままです。 マヤ文明は20進数を基本としていました。 ケルト文明は、12進数を使っていました。 英語に「eleven」と「twelve」やドイツ語に「elf」と「zwölf」があるのは、その名残です。 時間は、古代から現在まで、12または24進数になっていますね。 月も12ですね。 分や秒は60進数になっています。 n進数はいろいろなところに生きております。

コンピュータの世界では、16進数は2進数を4桁ずつ下位の桁から区切って読んでいけば良いので、 結構普及しています。12進数や60進数が普及しているのは、実は、隠れたメリットがあります。 10進数よりも約数(割り切れる数)が多いからです。約数を見てみましょう。


	10の約数:1, 2, 5, 10
	12の約数:1, 2, 3, 4, 6, 12
	16の約数:1, 2, 4, 8, 16
	20の約数:1, 2, 4, 5, 10, 20
	24の約数:1, 2, 3, 4, 6, 8, 10, 20
	60の約数:1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60
	360の約数:1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, 24, 30, 36, 40, 45, 60, 72, 90, 120, 180, 360
		

10よりも12の方が約数が多いですね。 同じように20よりも24の方が約数が多くなっています。 注目すべきは、360が7以外の1桁のすべての数で割り切れることです。

★整数を文字列に変換するためのメソッド

通常は、空の文字列と足し算すれば良かったのでした。


	""+1234		// "1234"という文字列にに変換してくれます。
		

タートル・グラフィックスでは、 formatIntegerメソッドがあります。 これは、長桁整数型あるいは整数型の整数値を、指定された最小桁数、最大桁数の数字から構成される文字列として 変換してくれます。 なお、整数値が最小桁数よりも少ない桁数の場合は、左側に0が入れられます。

 formatInteger( 最小桁数, 最大桁数, 整数値 )

	formatInteger( 5, 5, 1234 )		// "01234"という文字列にに変換してくれます。
		

これを表示したければ、一度文字列の変数に代入するのもよし、あるいは、直接printLineなどの パラメータに書いても構いません。


	String s = formatInteger( 5, 5, 1234 )		// 文字列の変数に代入する場合
	printLine( s );
	printLine( formatInteger( 5, 5, 1234 ) );		// パラメータに直接記述する場合
		

整数を符号なし16進数の文字列、8進数の文字列、および2進数の文字列に変換するには、 先に紹介したように次のようなメソッドが用意されています。 これらは、標準のJavaのライブラリ(JFCのIntegerクラス)に含まれています。

 Integer.toHexString( 整数式 )     …整数式を符号なし16進数の数字から構成される文字列に変換します
 Integer.toOctalString( 整数式 )     …整数式を符号なし8進数の数字から構成される文字列に変換します
 Integer.toBinaryString( 整数式 )   …整数式を符号なし2進数の数字から構成される文字列に変換します

これ以外のn進数への文字列への変換メソッドは用意されていません。 基本的に、コンピュータでよく用いられるのは、2進数と16進数で、特殊な場合だけ8進数も用いられます。 しかし、それ以外のn進数が用いられる場合は、まったくないからです。

		
	Integer.toHexString( 10 )		// → 16進数の文字列 "a"に変換されます
	Integer.toOctalString( 22 )		// → 8進数の文字列 "26"に変換されます
	Integer.toBinaryString( 8 )		// → 2進数の文字列 "1000"に変換されます
		

以下のプログラムも、またもや、startメソッドの中だけを記述しています。

		
	String  hex =  Integer.toHexString( 34 );
	String  binary =  Integer.toBinaryString( 34 );
	printLine( 34 + "の16進数表記は" + hex + "で、2進数表記は" + binary );
		

なお、変数に代入しなくとも、以下のように直接パラメータの部分に記述することができます。

		
	printLine( Integer.toHexString( 34 ) );
	displayDialog( Integer.toBinaryString( 34 ) );
		

■長桁整数と整数の間の変換

Javaには、キャスト(Cast)と呼ばれる式があって、基本型(文字列は除く)は変換したい型に変換させることができます。 キャストは、結びつき(演算優先度)が高いので、下記の式の部分には丸括弧をつけておいた方がよいでしょう。

 ( <変換させたい型> ) <式>

たとえば、以下の記述は、長桁整数型の式を整数に変換するのと、逆に整数型の式を長桁整数に変換しています。


	( int ) 39439L			// 整数の39439に変換されます
	( long ) 343773			// 長桁整数の343773Lに変換されます
		

以下のプログラムは、長桁整数を整数型の変数に代入し、整数型の変数を長桁整数に変換して表示しています。 なお、長桁整数型の変数に、整数を代入するときは、わざわざ、キャストを用いる必要はなく、自動的に変換されて 代入されます。startメソッドの中だけを記述しています。


	int x = ( int ) 39439L;
	printLine(  ( long ) x ) );
	long xx = 343773;		// この場合は、キャストを用いる必要はなく自動的に長桁整数として代入されます
		

ただし、長桁整数の値を整数型に変換したり、整数型の変数に代入するときに、 その値が、整数型で表されている範囲を超えていた場合は、 実行時エラーが起こります(エラーが起こらない実行環境では、ビット落ちした滅茶苦茶な値が代入されています)。


	int x = ( int ) (394393 * 2378333);
		

☆課題4-1(旧名課題3-5) 2進数の入力を10進数に直して表示

ダイアログに2進数を入力してもらうように表示します。何桁でも構いません。 入力を文字列として受け取り、それを10進数に変換してダイアログに表示するプログラムを作成しなさい。 ヒントは、displayInputDialogを使うのと、基数をパラメータとして指定できる方のconvertToIntegerを使います。 クラス名は、DisplayConvertedBinaryとします。コンパイルして実行してみなさい。

☆課題4-2(旧名課題3-7) 10進数の入力を2進数に直して表示

今度は、10進数をダイアログで入力してもらうようにします。 これは整数として受け取ります。 入力した数を2進数の数字から構成される文字列に直して表示するプログラムを作成しなさい。 ヒント:今度は整数として受け取りますので、displayInputIntegerDialogを用いるのと、 10進数を2進数の文字列に直すInteger.toBinaryStringを用います。 クラス名はDisplayBinaryNumberとします。コンパイルして実行してみなさい。

なお、出来る人は(ここ以降はできる人だけがやってください!)マイナスのときの値も表示するようにしなさい。ちなみに-1は、 2の補数表現されていて、32bitの整数では 0xffffffffですから、この値から(その数絶対値-1)を 引くようにします。この途中の計算はlong型で行なって下さい。 long型を強制的にint型に変換するには(int)(<式>)を用います。


4−3.条件分岐

■3つの条件分岐文

何かの条件が満たされたときは、処理を変えたい場合があります。 これを「条件分岐(Conditional Branch)」と呼んでいます。 Javaでは、条件分岐を行なう文のことを「if文」と呼んでいますが、 多くのプログラミング言語でもそのような条件分岐を行なう制御文は3つのパターンが用意されています。

■条件が満足されたときだけ実行される条件分岐(if-then文)

この条件分岐は、次のように記述します。

  if ( <条件式> ) <ブロック>

さて、条件式が満足されなかった場合はどうなるのでしょうか? その場合は、何もせずに次の処理に実行が移るだけです。 さて、<条件式>の細かな定義は後にして、実際にどのように記述するか、見ていきましょう。 たとえば、以下のプログラムは、マイナスの数が入力されても、絶対値を表示するようになっています。 またもや、startメソッドの中だけを記述しています。


		//入力された値の絶対値を表示するプログラム
			
		int  ikachan;
		ikachan = displayInputIntegerDialog( "整数を入力して下さい",  -72 );
		if ( ikachan < 0 ) {
			ikachan = 0 - ikachan;
		}
		displayDialog( "入力された整数の絶対値は" + ikachan + "です。" );
		

■条件式の書き方

最初の例では、条件式で「<」の記号を使いました。このように、両側の式の値を評価して、2つの値の比較を行なう 演算子のことを「比較演算子(Comparator)」と呼んでいます。言霊では、比較演算子を使った条件式は次のように記述します。

 <式> <比較演算子> <式>

比較演算子としては、次のようなものが使えます。


比較演算子意味使用例

> 左の式が右の式より大きいtakochan > 10
<左の式が右の式より小さいx < y + 10
>=左の式が右の式より大きいか等しいtakochan >= 10
<=左の式が右の式より小さいか等しいikachan <= 0
==左の式が右の式と等しいtakochan == ikachan * 2
!= 左の式が右の式と等しくないikachan != 0

記号は全部半角で入力するようにしてください。しかも、記号と記号の間に空白を入れないでください。 ですから、「> =」みたいに、不等号と等号の間には空白が入ってはいけません。 それから、イコールの入った不等号は不等号の方から記述します。「>=」を「=>」と書くとコンパイラに叱られます。 同じように、「=<」もコンパイラに叱られます。また、等しいという意味のイコールは 「==」イコールを2つ書かなければならないことに注意して下さい。 Javaでは、イコール1つの「=」は、代入演算子、イコール2つの「==」は、等号演算子と明確に区別されています! 条件式も一般の式と同じように、評価されます。ただし、評価結果は論理値になります。 条件式が満足される場合は、「true」という論理値に評価されます。 また、満足されない場合は「false」という論理値に評価されます。

■条件が満足されたないときの処理も指定できる条件分岐(if-then-else文)

  if ( <条件式> ) <ブロック>
 else <ブロック>

最初の条件分岐の記述方法では、条件に該当しない場合は、何もしないで次の処理に実行が移りますが、 こちらの条件分岐では、該当しない場合に、2番目に書かれたブロックを実行するようになります。 次のプログラムは、入力された数が偶数か、奇数かを表示するものです。 整数剰余を用いているところに注目してください。 またもや、startメソッドの中だけを記述しています。

		
		//入力された数が偶数か、奇数かを判定するプログラム
		
		int  verifier;   // 吟味する数を入れる変数の宣言

		verifier = displayInputIntegerDialog( "正の整数を入力して下さい", 11 );

		if ( verifier % 2 == 0 ) {
			displayDialog( verifier + "は偶数です" );
		} else  {
			displayDialog( verifier + "は奇数です" );
		}
		

よく間違う文法エラーは、「else 」の後に反対の条件式を書いてしまうことです。 律儀な人に多いのですが、既に最初の条件式で満足しないことがわかっているのですから、 反対の条件をわざわざ書く必要はありません。

☆課題4-3(旧名課題4-1) ユーザの入力で色を分ける

上のプログラムを利用して、ユーザに整数を入力してもらい、奇数だったら青色で、 偶数だったら赤色で円(正60角形)を表示するようなプログラムを作成しなさい。 クラス名は、OddBlueEvenRedで作成し、コンパイルして、実行させなさい。 ヒント:回転角度は6度です。

■複数の条件を指定できる条件分岐(if-then-elseif文)

if文については、第3番目の書式で代用できますので、それで記述します。以下の記述で、[ A ]は、Aを省略可能であることを 示し、[ A ]…はAを0回以上繰り返せることを示しています。

if ( <論理式> ) <ブロック>
[ else if ( <論理式> ) <ブロック> ]…
[ else <ブロック> ]

上記の文法の規則の中で[]は、省略可能であることを意味しています。また、…は、何回繰り返しても 良いことを意味しています。ですから、最後の「そうでないならば」のブロックは省略することができますし、 途中の「をして、<条件式>ならば」のブロックは、何回(0回も含む)繰り返しても良いことになります。 途中のブロックが省略された場合は、2番目の条件分岐と同じ意味ですし、途中のブロックと最後のブロック がすべて省略された場合は、1番目の条件分岐と同じです。最後のブロックだけ省略することも可能です。 その場合は、すべての条件に当てはまらないときは何もせずに次の処理へ進みます。 途中のブロックが1回以上ある場合は、条件式は上から順番に調べられていきます。

else if 文が複数ある場合は、上から順番に条件式を評価し、条件を満足するif文の後で指定されたブロックを選択し、 実行するということです。条件式が上から順番に一つずつ評価されることに注意してください。 たとえば、整数型の変数xに何らかの正の整数値が入っているものとしますと、以下の記述は、上から順番に条件式を評価して、 対応するメッセージをターミナルに出力します。またもや、startメソッドの中だけを記述しています。

		
		// 成績判定プログラム
		
		int  score; 
		score = displayInputIntegerDialog( "あなたの成績を入力して下さい(100点満点)", 100 );

		if ( x >= 80 ) {					// 80以上
			printLine( "成績はA" );
		}
		else if ( x >= 60 ) {			// 60以上でかつ80未満 
			printLine( "成績はB" );
		}
		else if ( x >= 40 ) {			// 40以上でかつ60未満
			printLine( "成績はC" );
		}
		else {						// 40未満
			printLine( "落第" );
		}
		

あるいは、現在の時間が整数型の変数hourに求まっているとしましょう。 このときに、8時と12時と、午後7時(19時)ならば、食事に行くような条件分岐を書いてみましょう。 タートル・グラフィックスでは、 getHour メソッドで現在時間を求めることができます。 またもや、startメソッドの中だけを記述しています。


		// 規則正しい食生活プログラム

		int hour = getHour( );  // タートル・グラフィックスのライブラリで現在時間を求めることができます。
			
		if (  hour == 8 )  {			printLine( "朝食を食べましょう" );  }
		else  if (  hour == 12 )  {	printLine( "ランチを食べましょう" );  } 
		else  if (  hour == 15 )  {	printLine( "午後の紅茶を飲みましょう" );  } 
		else  if (  hour == 19 )  {	printLine( "ディナーを食べましょう" );  }
		else  {					printLine( "食べ過ぎにご用心" );  }
		

■入力を判別してみる

★実習4-3 割り切れる数どうかの判定

ある数をダイアログかターミナルで入力してもらって、それが13で割り切れる数かどうか判定します。 クラス名はPractice0402という名前で新規クラスを作成し、コンパイルし、実行しなさい。

☆課題4-4(旧名課題4-2) 元号と西暦の変換

まず、次のような表示を出します。「明治=1,大正=2,昭和=3,平成=4,西暦=5」の中から選んで下さい。 1〜4までの場合は、元号と年から西暦を求めます。5の場合は、逆に西暦から元号と年を求めます。 さて、次に年を入れてもらいます。たとえば、ユーザが4(=平成)を入力し、19を入力してもらったら、 「平成19年」ということですから、「西暦」と表示し、その後「2007」と表示させます。 あるいは、ユーザが5(=西暦)と入力し、1998を入力したら、「平成」と表示し、その後「10」と表示します。 コンソールに一行として出力しても構いません。 ちなみに、明治から平成までの元号の元年(最初の年)は、以下の通りです。 もし、西暦で1868年以前を入力された「明治以前」という表示だけで結構です。 また、西暦1989年以降は、すべて「平成」と年数で表示してください(たとえ、3080年でも)。 クラス名はNengoConverterという名前で新規クラスを作成し、コンパイルし、実行しなさい。

明治元年西暦1868年      昭和元年西暦1926年
大正元年西暦1912年      平成元年西暦1989年

■if文を記述するときに間違いやすい例

例1:以下ような場合は、コンパイラがエラーを報告してきます。


		if ( money >= 100 ) {
			........
		}
		else ( money < 100 ) {	// いちいち反対の条件を書かなくても良いのです
			.......
		}
		

例2:if 文やwhile文の条件式の指定の括弧やfor文の直後にセミコロンを書いてはいけません。 コンパイラは、この記述の場合は空文があり、制御文は、そこで強制的に終わりになって、 次に別の新たなブロックが続いているとして解釈して、エラーを出してきません。


		if  (  money == 30  ) ;  { 	// エラーが報告されませんが、うまくいきません
				.....				// 後ろのブロックは単体のブロックとして見なされます
		}

		if  (  money == 30  )  { 
				.....
		} else  ;  {		// elseの後もエラーが報告されませんが、うまくいきません
				......
		}
		

例3:条件式の中に、代入文を書いてはなりません。等しいことを比較する演算子は==です。


		if   (  money = 300 )  {	// これもコンパイル時にエラーにされます、C/C++ではエラーになりません
				......
		}
		

例4:else if文では、else ifのelseを書き忘れてしまうと、2つのif文になってしまいます。

		
		if  ( money > 10 ) {    ....   }
		if  ( money  >  5  )  {    ......  }		// 別のif文になってしまいます、moneyが10より大きければこちらも実行されます
		else  { ........ }
		

例5:else if文では、前提条件は書かなくてもいいのです(御丁寧に書く人がいる、そう、あなたです!)。 else if文では一番上のifから下のelse ifに向かって順番に条件式が評価されていくことを思い出してください。 下のelse ifの中では、もう上のifで条件式が評価されて、「満足されなくて」下に制御が移ってきたのですから、 その「満足されなかった」条件をわざわざ指定する必要はないのです。


		if ( x >= 80 ) {
			printLine( "成績はA" );
		}
		else if ( x >= 60,  x < 80 ) {	//  こんな記述は間違い、そもそもx <80は書く必要ありません
			printLine( "成績はB" );
		}
		else if ( x >= 40, x < 60 ) {	//  カンマで区切って複数の条件式を書いても機能しません
			printLine( "成績はC" );
		}
		else ( x < 40 ) {			//  例1と同じ間違い、それでも書きたがる人はいます
			printLine( "落第" );
		}
		

■AppleScriptでの条件分岐

■ExcelのIF関数で条件分岐をやってみる

Microsoft ExcelのIF関数では、2番目および3番目の仮定文と同様なことができます。

1)Excelを起ち上げて、「ファイル」メニューから「新規作成」を選んで下さい。あるいは、 プロジェクトギャラリーが出ている場合は、「新規」のタブを選んで、「Excelブック」をクリックします。

2)「ツール」メニューの「アドイン…」を選んで、 出てくるダイアログで「分析ツール」にチェックマークを入れておきます。 実は、この後に使う「RANDBETWEEN」は分析ツールにしか入っていない関数なのです。

3)A1のセルに、「乱数」と入力します。B1のセルに「点数」、C1のセルに「ランク」と入力します。 学生の点数をいちいち入力するのは面倒なので、乱数で作成しましょう。 A2のセルには、標準ツールバーの「fx」のボタンを押すか、 数式バーの「=」ボタンを押して、次のように入力し、Return(Enter)を押します。 あるいは、関数のペーストダイアログが出ている場合は、「関数の分類」で「数学/三角」の分類を選んで、 その中から、RANDBETWEENを選んで「最小値」に0を、「最大値」に100を入力してOKボタンを押します。

		
		=RANDBETWEEN(0,100)
		

4)A2のセルには0〜100までの数値が表示されたと思います。このように適当な数を返してくることを 「乱数(Random Numbers)」と呼んでいます。 白い十字カーソル(╬←ちゃんと似ていなくて申し訳ない)を、A2のカーソルの右下の青い小さな■に持っていくと、 カーソルの形が黒の「+」に変わります。この状態で、A2からA41ぐらいまで、ドラッグして下さい。 A2の式の内容がコピーされて、0〜100までの乱数の値が表示される筈です。

5)A2からA41までの乱数は、毎回値が入力する度に変わってしまいます。 これでは困りますので、どこかの時点の乱数の値で固定して、それをB2からB41までにコピーしたいと思います。 そこで、A2のセル上でマウスクリックして、ボタンを離さないでドラッグをA41まで行ないます。 これで、A2からA41までが選択されました。 ここで、「編集」メニューから「コピー」を選びます。 次に、白い十字カーソルをB2に持って行き、クリックを一回します。そして、「編集」メニューから、 「形式を選択してペースト」を選びます。 次のようなダイアログが出てきますので、次のようにペーストの欄で「値」を選んでください。

6)次に、C2にも、「fx」のボタンを押すか、数式バーの「=」ボタンを押して次のように入力してReturn(Enter)を 押してください。 関数ペーストのダイアログが出ている場合は、「関数の分類」で「論理」の分類を選んで、その中からIFを選びます。 論理式には「C2>=50」を入力し、真の場合には「"A"」を偽の場合には「"B"」を入力します。 文字列なのでダブルクォーテーションマーク(")で囲んで下さい。

		
			=IF(B2>=50,"A","B")
		

7)これも先ほどのようにして、C2からC41ぐらいまでドラッグしてください。 このIF関数が、ちょうど2番目の仮定文に相当します。B2セルの値が50以上ならば、Aという文字列を評価し、 そうでないならばBという文字列を評価します。 なお、乱数の関数はセルを変更するたびに再評価されますので、A列の値はどんどん変わっていきますが、 B列は、ある時点でコピーした値が残されたままになっています。

★実習4-4 IF関数を用いて4段階評価する

上記は2段階評価でしたが、4段階評価(80点以上はA、60点以上はB、40点以上はC、それ未満はD)に してみてください。たとえば、3段階評価にするには、先ほどの数式を数式バー上で、以下のように編集します。

		
			=IF(B2>=66,"A",IF(B2>=33,"B","C"))
		

このようなIF関数の使い方は、ちょうど3番目の仮定文に相当します。

★実習4-5 COUNTIF関数を用いてヒストグラムを表示する

全員の点数の平均点を求めてみましょう。AVERAGE関数を用います。次に、4段階のそれぞれの段階の人が 何人いるのか数えてみましょう。ある値が指定されたセルの範囲に何個あるのかを求めるのは、COUNTIF関数です。 Aの人が何人、Bの人が何人、Cの人が何人、Dの人が何人いるか、棒グラフで表示させてみて下さい。 社会にでたら、ここまでぐらいExcelが使えることは常識的に求められます。 同じようなことは、「ツール」の「分析ツール」にある「ヒストグラム」でもできます。

■AppleScriptからExcelを使う


4−4.論理式

■条件分岐のネスト

たとえば、整数の変数「この月」に1から12までのいずれかの月を示す数が入っているとします。 これが小の月か大の月かを判定しようと思います。 タートル・グラフィックスのライブラリでは、 getMonthメソッドで 現在の月を求めることができます。 昔から「西向く侍(さむらい)小の月」というフレーズで覚えられてきました。 2・4・6・9・11月は小の月、つまり月が31日に満たない月なのです。 なぜ「侍が11なのか?」という疑問があるでしょうが、侍(さむらい)を「士」と書き、語呂合わせしています。 この士が漢数字の十一を縦に書いたのに似ているので、こんなフレーズで覚えられてきたということです。 「水兵Liebe(愛する)僕の船So曲がーるShipsクラークか」とか、「貸そうかな?まあ当てにすな、酷すぎる借金」なんて 語呂合わせと同じです。 余談はともかく、小の月と大の月を考えてみると次のように、8月を超えるかどうかで、奇数の月と偶数の月 が丁度逆になるように記述することができます。 if文もこのように多重に組み合わせることができます。

		
		int month = getMonth( ); 
		// あるいは  int month = displayInputIntegerDialog( "月を入力してください", getMonth( ) ); 

		if ( month % 2 == 0 ) { //偶数の月の場合
			if ( month <8 ) {
				printLine( month + "月は小の月です。" );
			} else {
				printLine( month + "月は大の月です。" );
			}
		} else { //奇数の月の場合
			if( month > 8 ) {
				printLine( month + "月は小の月です。" );
			} else {
				printLine( month + "月は大の月です。" );
			}
		}
		

■条件式の評価

記号は全部半角記号を用います。言霊でやったので意味は省略します。 しかし、「等しいこと」を示す「等号」は=ではありません。Javaでは==と、イコール記号を2つ連続して記述します。 =は、代入のために用いられて違う意味になっています。また、「等しくない」ことを示す記号は「!=」です。 注意して下さい。また、「>=」や「<=」では、「=」が後(右側)になっています。前(左側)に記述しないので 注意してください。これらの2つの記号文字が続く記号は、空白で間を空けてはいけません。連続して記述して下さい。 たとえば、「= =」や「> =」というように空白をあけてしまうと、コンパイラはエラーにします。

▼条件式:
 <式> < <式>    左側の式の評価値が右側の式の評価値より小さいことを示す
 <式> <= <式>    左側の式の評価値が右側の式の評価値より小さいか等しいことを示す
 <式> > <式>    左側の式の評価値が右側の式の評価値より大きいことを示す
 <式> >= <式>    左側の式の評価値が右側の式の評価値より大きいか等しいことを示す
 <式> == <式>    左側の式の評価値が右側の式の評価値と等しいことを示す
 <式> != <式>    左側の式の評価値が右側の式の評価値と等しくないことを示す

条件式は、条件を満足すればtrueに、 あるいは満足しなければfalseに評価されます。 ですから、次のようにそれを論理値としてターミナルに表示させることもできます。

		
		int x = 34;
		printLine(  x > 20 );   // trueが表示されます
		

■論理式の導入

条件文を多重に組み合わせると、上の例のように同じことを何回も書かなければならないという場合があります。 そのために、1つの仮定文で複数の条件式を記述するために、「論理式(Logical Expression)」が一般のプログラミング言語 では用意されており、もちろんJavaでも記述することができます。 記号は全部半角記号を用います。!は否定、&&は「かつ」、||は「または」を 意味します。

▼論理式:
 <条件式>
 ! <論理式>             // 否定を表す
 <論理式> && <論理式>       // 論理積「かつ」を表す
 <論理式> || <論理式>        // 論理和「または」を表す

!は、そのままでも使っても良いでしょうが、!(<条件式>)と丸括弧で囲った方が読みやすいでしょう。 評価の優先順位は、!が一番高く、次に&&で、最後は||です。なお、これらの演算子も左結合性なので、 ||の場合は、左側の論理式がtrueに評価された場合は、右側は評価しません。 また、&&では、左側の 論理式がfalseに評価された場合は、右側は評価しません。 それから、「または」を表す||は、縦棒2つです。 大文字のI(アイ)や小文字のl(エル)ではないので注意して下さい。縦棒は、JIS配列のキーボードでは、¥マーク キーをShiftキーを押しながら入力します。これらの論理式について、論理値を記述しておきます。


論理式(否定)評価結果
!true false
!false true

論理式(論理積)評価結果論理式(論理和)評価結果
true && true true true || true true
true && false false true || false true
false && true false false || true true
false && false false false || false false

「かつ」は両方の条件式が満足するときだけ「true」に 評価されます。「または」はどちらかの条件式だけが満足すれば「true」に評価されます。 加えて、「または」の場合、左側の条件式が「true」と評価された場合で、 右側の条件式は評価されません。 それから、「&&」と「||」はどちらが優先順位が強いかと言えば、 たいていのプログラミング言語では「かつ」の方が優先順位が強い演算子になっています。 「かつ」が「または」に勝つとでも覚えておいて下さい。 ただし「!」という否定が演算子的には一番強い結合力を持っています。 下記にいくつかの条件式の例を記述します。

		
		month%2 == 0 && month < 8	//偶数の月の小の月の条件式
		100<=x &&  x<=200			// 「100<=x<=200」とは書けません!注意して下さい!
		x==0 || x==1					//「x == 0 || 1」とは書けません!注意して下さい!
		!( x <100 ) && x%17 == 0		//否定には丸括弧を付けた方がわかりやすいでしょう
		

また、論理式も最終的には、論理値として評価されます。以下のプログラムの断片も、論理値が表示されます。

		
		int x =25;
		printLine(  x >= 100 && x <= 200 );		// falseが表示されます。
		

★実習4-5 小の月か大の月かを判定する

論理式を利用して、例題のプログラムを書き換えて完成させてみなさい。 繰返し文を利用して、その月を1から12まで変化させなさい。 そして、論理式を使って1つの仮定文で小の月か大の月かを判定してコンソールに表示させます。 クラス名はPractice0405で作成し、コンパイルし、実行します。

■論理式の書換え規則

以下の書換え規則はド・モルガンの法則として 有名です。論理式をPとQという形で記述します。日本語とJavaでの記述の両方を示します

 (PでありかつQである)でない !(P && Q)    ⇔   PでないまたはQでない  !P || !Q
 (PであるまたはQである)でない !(P || Q)    ⇔   PでないかつQでない  !P && !Q

どこかの女の子が自分の彼氏の条件として、「(貧乏または不潔)でない」と言ったとしましょう。 この条件式は、上記の書換え規則により「貧乏でないかつ不潔でない」と言えることができます。 そんな世迷い言はともかく、Javaでどのように記述するか例を見てみましょう。 コメントの中に等しい記述を書いておきます。 2番目の例は数直線を描いて確かめてみて下さい。

		
			!(x==0 ||  x==100)				// !(x==0) && !(x==100)   もしくは       x !=0 && x != 100
			!(100<=x && x<=200)			// !(100<=x) || !(x<=200)  もしくは  x<100 || x>200
		

それ以外にも、不等号や等号に関して、簡単な書換え規則が考えられます。 いくつか例を紹介しますが、ここに挙げている以外にも自分で考えてみて下さい。 下記の例でAとBは何らかの式であると仮定します。

		
			!(A==B)		// A != B          等号と不等号の変換
			A<=B		// A > B || A==B       不等号の分解
			!(A<=B)		// A > B           逆の不等号への変換(その1)
			!(A<B)		// A >= B          逆の不等号への変換(その2)
		

☆課題4-5(旧名課題4-3) 閏年かどうかを判定する

現在採用されているグレゴリオ暦では、 閏年の計算を以下のように求めています。 これで1暦年は平均365.2425日で、約3320年に1日の割合で暦と季節がずれることになります。 1年の平均回帰年(約365.242199日)と 食い違いがあるからです。

365+1/4-1/100+1/400=365+0.25-0.01+0.0025=365.2425という計算になります。 ちなみに、古代マヤ文明のカレンダーでは、1暦年を365.2420日としており、グレゴリオ暦よりも精度が高いのでは ないかとも言われています。 さて、皆さんの課題はダイアログを出して西暦のある年を入力してもらい、それが閏年かどうか表示するプログラムを作成するという ものです。 クラス名はLeapYearで作成し、コンパイルし、実行します。 実行時に1900年、2000年、2004年、2007年などを入力値として入れてみて、それぞれ平年、閏年、閏年、平年であると 表示されるかどうか確かめなさい。

■AppleScriptでの論理演算


<<Previous Lecture >>Next Lecture