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

第5回正しく計算させるための基本、演算法則

演算法則

今回は、演算法則に注目します。演算法則を確認しておかないと意図した計算結果が得られません。コンピュータは律儀に演算法則を守るため、⁠題意からして、それは無いだろう」という計算式も、そのままきちんと実行してしまいます。

演算法則は、いわば算数・数学の基本中の基本です。大工さんに例えれば、⁠正確に早く釘を打ち、真っ直ぐ鋸を引く」という技にあたるのではないでしょうか。中学校の技術家庭科の時間に、いすや本立てを作られた方は少なくないでしょう。鋸で切るのは簡単なのですが、真っ直ぐに引くことがなんと難しかったことでしょう。失敗を繰り返しながら上手になっていきましたよね。数学やプログラミングも同じです。理にかなって適切に式を組み立て、コーディングする習慣をつけましょう。

図5.1 匠の技も基本から
図5.1 

演算の優先順位

左方優先

基本的に、演算は式の左側から右側へ行います。次の式を見てください。

右から計算してみましょう。

この式は左から計算しても、右からでも同じ結果になりましたが、次の式はどうでしょうか。

いかがですか、右から計算した結果と、左から計算した結果とでは違うのが一目瞭然です。⁠計算は左から右へ」という原則を再確認してください。人間は優れた計算機械です。このような計算ルールをいったん身につければ、問題の意図するところを読み取って、正しく計算式を組み立てようとします。しかし、コンピュータは人間がプログラムに書いたとおりにしか計算しません。⁠ここは面積を計算するところだから、こうして丸括弧を入れて計算しないとね…」などとは、コンピュータは気を利かさないのです。

人間が正しく厳密にプログラムを作成し、コンピュータに指示しない限りは、問題の意図する計算結果が得られないのです。

演算子の優先順位

演算子には優先順位があります。何の指定もなければ乗算・除算は加算・減算よりも先に計算しなければなりません。次の式の左辺は右辺のように計算しなければなりません。

しかし、場合によっては1 + 2 だけは、意味があって先に計算をする必要があるとします。そのときには、先ほどの式を次のように書き直さないと意図する計算になりません。

各種計算式をプログラム化する場合には、計算の意図を間違いなくプログラミング言語で指示してやらなければなりません。適切に丸括弧(「パーレン」ともいう) を用いて計算の順序を指示する癖をつけましょう。

交換法則・結合法則・分配法則

演算法則は表5.1に示すように3種類あります。

表5.1 演算法則一覧
法則名演算の例
交換法則a + b = b + a  ab = ba
結合法則(a + b) + c = a + (b + c)  (ab)c = a(bc)
分配法則a(b + c) = ab + ac  (a + b)c = ac + bc

演算法則についての表に加算と乗算しか現れないのには意味があります。次の例を見てください。

このように、交換法則は引き算や割り算には適用できません。ですから、次のように読み替える必要があるのです。

紙の上で計算するときには、こういう演算法則を無意識に使って計算ができる人でも、ソースコードの修正を行う際、変数を単純に交換しただけで済ませてしまったりすることがあります。心当たりはありませんか? また、次の例を見てください。

これらも適宜加算や乗算に読み替えてから結合法則を適用すれば問題ないのです。

問題1:台形の面積を計算するプログラムを作成して下さい。

図5.2の台形の面積を計算する式をJava言語で記述し、計算結果を表示してください。なお、台形の面積の公式は次の通りです。

(1) 公式に従い、電卓で台形の面積を計算しましょう。

(2) 公式に従い、Java 言語で数式を書いてみましょう。

(3) ソースコードを作成し、実行してみましょう。

図5.2 台形の面積
ヒント
次のソースコードの9行目に適切な計算式を記述し実行してみましょう[1]⁠。
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//filename : Daikei_No_Menseki
class Daikei_No_Menseki {
  public static void main(String[] args) {
    float menseki = 0; // 例題中ではA:単位[cm^2]
    int jyo_hen = 5; // 例題中ではa:単位[cm]
    int ka_hen = 10; // 例題中ではb:単位[cm]
    int takasa = 4; // 例題中ではh:単位[cm]
    
    menseki = ここに計算式を記述する
    
    System.out.println("面積は" + menseki + "[cm^2]" );
  }// end of main
}// end of class

問題2:丸棒と中空円筒の断面積の比を計算するプログラムを作成しましょう。

図5.3のように、直径d = 30[mm]の丸棒の断面積をA[mm2]、外径d1 = 30[mm]、内径d2 = 20[mm] の中空円筒の断面積をA1[mm2] としたときの比(A_1)/A[-]を導き、Java言語で記述してください。

図5.3 丸棒と中空円筒

問題1:解説 台形の面積を計算するプログラムを作成して下さい。

(1) 公式に従い、電卓で台形の面積を計算しましょう。

電卓を使って計算すると、30[cm2] となります。もし、違う結果が出たのならば、それは計算の手順が誤っています。そのままプログラムを組んでも正しい結果を出すことが出来ないでしょう。こうしてあらかじめ計算ミスを予測・防止することができます。

(2) 公式に従い、Java言語で数式を書いてみましょう。

case 1.

まずは、計算の優先順位が体得出来ていないために犯す間違いを紹介します。

menseki = jyo_hen + ka_hen * takasa / 2;

乗除算は加減算に優先して演算されるため、この式が意味する計算は次の式と等価になります。

面積 = 上辺 + ((下辺 × 高さ) ÷ 2)

いちいちパーレンをつけるのは面倒だと感じるかもしれませんが、

などという計算を行う場合には、式中にないパーレンを補足し、

演算結果 = ( a + b ) / c ;

とソースコードを記述しなければなりません。以上のことから、次のように記述しましょう。

menseki = (jyo_hen + ka_hen) * takasa / 2;
case 2.

演算の優先順位を正しく指示しているにもかかわらず、次のような式を記述してしまうと、Java言語の仕組み上、意図する計算結果を得られません。

menseki = 1 / 2 * ( jyo_hen + ka_hen ) * takasa;

これは数式としては正しいのです。しかし、式が左側からJava言語によって評価され、整数の除算1 ÷ 2の計算結果が0 となります。1 ÷ 2 = 0 … 2 だからです。これを防ぐためには、最初の数値リテラル1 に対して、次の策が考えられます。

  1. (a) float型にキャストを行う
  2. (b) 1.0 あるいは 1f などとその数値リテラルがfloat型であることを明記する

整数型の除算と実数型の除算とでは仕組みが異なることは、見落としやすいので注意しておきましょう。

(3) ソースコードを作成し、実行してみましょう。

(1)⁠2)より、次のようなソースコードが例示できます。

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//filename : Daikei_No_Menseki.java
class Daikei_No_Menseki {
  public static void main(String[] args) {
    float menseki = 0; // 例題中ではA:単位[cm^2]
    int jyo_hen = 5; // 例題中ではa:単位[cm]
    int ka_hen = 10; // 例題中ではb:単位[cm]
    int takasa = 4; // 例題中ではh:単位[cm]

    menseki = (float) 1 / 2 * ( jyo_hen + ka_hen ) * takasa;

    System.out.println("面積は" + menseki + "[cm^2]" );
  }// end of main
}// end of class

ソースコード中の数値リテラルを「マジックナンバー」といい、後のプログラム修正等で困ったことになりやすい存在です。この数値リテラルを、変数や定数変数で置き換えれば、変更や修正に対応しやすいソースコードになります。変数名はコメント文の代わりにもなります。努めてこの方針を守る習慣をつけましょう。

問題2:解説 丸棒と中空円筒の断面積の比を計算するプログラムを作成しましょう。

(A_1)/Aは、円の面積が(πd^2)/4であることから導出します。導出過程を示します。

[-]は、単位なし、の意味です。面積を面積で除したために、単位が無くなったのです。

次にソースコードを示します。9行目が肝心の式です。この式からパーレンを外してしまったらどうなるでしょうか。ここまで読んでこられた方ならどうなるかお分かりでしょう。実際にたくさんの計算を行うプログラムを書いていると、意外とそのようなケアレスミスを起こしてしまうものです。

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//filename : Danmenseki_no_Hi.java
class Danmenseki_no_Hi {
  public static void main(String[] args) {
    float A1_by_A = 0; //断面積の比:単位[-]
    float d = 30; //円柱の直径:単位[mm]
    float d1 = 30; //円筒の外径:単位[mm]
    float d2 = 20; //円筒の内径:単位[mm]

    A1_by_A = ( d1 * d1 - d2 * d2 ) / ( d * d );

    System.out.println("A1 by A is " + A1_by_A + "[-]" );
  }// end of main
}// end of class

おすすめ記事

記事・ニュース一覧