Sachool Engineering Blog

プログラミング学習の記録

計算機のアルゴリズム

| Comments

どうも新人エンジニアのhondaです。
4月から入社しました。プログラミングは未経験でしたが、何かをつくる仕事がしたいと思い、入社しました。もうすぐ入社してから1ヶ月が経つことになりますが、身に着けなければならないことが山積みで、日々勉強です。毎日新たな知識・技術を身につけていく日々ですが、これまで知らなかったコンピュータ・ソフトウェアの仕組みを学んだり、エンジニアが開発で使う最新のアプリケーションにふれられるのは、刺激的で、充実した日々です。
さて、今回は私が新人研修の中で取り組んでいる課題を紹介したいと思います。それは電卓のアルゴリズムをつくるというものです。課題は以下のとおりです。

課題


+-×÷の機能がある電卓のアルゴリズムを考えよ。またそのプログラムを作成せよ。
最初に数値、記号、数値、記号・・・と入力をうけとり、=が入力された時点で計算結果を出力する。
数値の個数は制限なし。以下計算例。

4÷2+4×3=14
2+3+4×7-1=32

※今回は最初に式すべて投入されることが前提とする。
「2+3×4=」ここまで1度に入力して計算する。

課題に取り組む


まじかー。×÷とかどうやったらええんやーーーー????

結局この課題の面倒な点は、

1.×÷があるから、前から順に計算できないこと。
2.入力される数値と記号の個数が定まらないこと。

の2点だと思ったので、これを解決する方法を考えた。

1の解決策


ここで問題なのは計算の順序だ。×÷がある箇所は先に計算を済ませないといけない。
以下のアルゴリズムを考えた。

1.計算記号を前から順に調べる
2.×÷記号があれば左右の数字を使って計算

そして、+-を計算するのだが、

3.+-記号があればその左右の…

って、左右の数値は計算結果じゃないじゃん。これ計算できなくね?
ここが悩んだところだった。
×÷の計算結果ってどうすんの?計算結果を入れておく変数つくるのか…
でもさらに変数つくっても、どんな感じで計算結果代入すればいいんだろう?

ここで突然のひらめきが
×÷の計算結果を左右の数値の右側に代入していくことで、×÷の計算結果を×÷が続いている部分の一番右側まで運んでくる。次に+-の記号の左にある数値と、×÷の右端の数字に代入されている数値を足し引きすればいいのでは?(例えば、3+7×8÷2×5-4=であれば、掛け算・割り算の計算結果は5の位置に代入される。次に+-を計算するので、3と”5の位置にある数値”を足し合わせる)。

めっちゃめんどくさいやん。でもこれ以外思いつかない…
とりあえず2番目の問題に移ろうかな

2の解決策


入力の受け方は、結局は”=”が入力されたら、入力をストップすればいいわけだからアルゴリズムはそんなに難しくなさそう。

1.数値の入力を受け付ける
2.記号の入力を受け付ける
* "="が入力されるまで1と2を繰り返す

意外と簡単だった。でもこれってどうやってコードにするんだろう。
そもそも入力を受け付けるってどうやるの???
フローチャート作成後はjavaで実装することになっていたのだが…
プログラムってどうやって入力受け付けるんだ???
と不安に思っていた。今考えると、そんな難しいことではないと分かるのだけど、
当時の私にとっては、相当面倒なことになるのではと不安だった。

さあ実装するぞ


上記のアルゴリズムに基づいてフローチャートを作成し、それをjavaにて実装した。
事前にjavaの書籍『スッキリ分かるjava入門』にてしっかり要点をおさえた。配列の使い方、入力の受け付け方、while文の使い方を覚えいよいよ実装に入った。
そして出来上がったコードがこちら

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class Dentaku2 {
  public static void main (String args []) {

    //number[]は数値、symbolは計算記号を順に代入

    int[] number;
    number = new int [15];
    String[] symbol;
    symbol = new String [15];

    //数値と記号の入力を受け付ける

    int i = 0;
    do{
      System.out.println("数値を入力してください");
      String numberString =
            new java.util.Scanner(System.in).nextLine();
      number[i] = Integer.parseInt(numberString);
      System.out.println("計算記号を入力してください");
      String symbol2 =
            new java.util.Scanner(System.in).nextLine();
      symbol[i] = symbol2;
      i++;
    }while (!(symbol[i-1].equals("=")));

    //×÷の計算を行い、結果を右側に送る

    i = 0;
    while (!(symbol[i].equals("="))){
      if (symbol[i].equals("*")){
        number[i+1] = number[i]*number[i+1];
      }else if (symbol[i].equals("/")){
        number[i+1] = number[i]/number[i+1];
      }
      i++;
    }

    /*+-を計算
    まず+-があるところを探す
    +-を見つけたら、その右側で再び+-があるところをさがす
    再び+-を見つけたら、その左側の数値(ここに×÷の計算結果が入っている)と足し引きする
    */

    i = 0;
    while(!(symbol[i].equals("="))){
      if(symbol[i].equals("+") || symbol[i].equals("-")){
        int m = i+1;
        while(!(symbol[m].equals("+") || symbol[m].equals("-")
                                       || symbol[m].equals("="))){
          m++;
        }
        if (symbol[i].equals("+")){
          number[m] = number[i] + number[m];
        }else{
          number[m] = number[i] - number[m];
        }
      }
      i++;
    }

    //計算終了、結果を出力

    System.out.println(number[i]);
  }

めちゃ複雑になった。特に×÷の計算後の+-のところ。
もっとシンプルで簡単な方法あるのかなと思いつつも、他の方法を思いつかない。
そして、すごく実装に時間がかかった。10時間くらいはかかったと思う。 それでも、基本的なコードだけで意外と電卓くらいなら作れちゃうんだなぁ、と驚いた。

まとめ


アルゴリズムって難しいな。これが思いつく限りベストな方法なんだけど、本当にベストなアルゴリズムかは確かめられないという…
いろいろ悩みながらもアルゴリズムをひねり出すのは結構頭をつかうし、時間もかかった。プログラムの書き方も試行錯誤しながらなんとか動くものを書いた。
総じて時間のかかる課題だったけど、結局自分の頭で(天下り的にではなく)何かをひねり出すことがいい経験になっていると感じる。
一つ一つの課題に数日がかりで時間をかけていて、プログラミングスキル自体は急速に身についているわけではないのだけど、それでも自分の力で考え抜いて答えを出す力はついている気がする。
エンジニアの仕事がどんなものかはまだまだ分からないのだけど、一つ思うのは、ソフトウェア開発の世界は日々技術が進歩していくので、当然エンジニアもそれについていかなければならないわけで、最先端についていく(あるいはそれを生み出す)には自分の頭で考えて、既存のものに頼らずに問題を解決する力が必要になるのだろう。そうだとすれば、今やっている課題は、エンジニアとしてのスキルそのものだけでなく、その基礎となる姿勢を身に着ける助けになっていのでは???(というポジティブシンキング)。

今もまた新たな課題を与えられ、結構四苦八苦しながら取り組んでいるのだけど、考え抜く姿勢を持って取り組んでいきたい。

Comments