Aritalab:Lecture/Programming/Java/Calculator

From Metabolomics.JP
< Aritalab:Lecture | Programming | Java
Revision as of 11:13, 20 October 2010 by Adm (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Stack; import java.util.StringTokenizer;

/**

* @author foo
* 逆ポーランド記号電卓、および普通の記法の電卓
*/

public class Calculator

 {
   static final int NUMBER = 0;
   /**
    * 与えられた文字が数字なのか、オペレータなのかを判定する関数
    * オペレータの場合は優先度を返し、数字の場合はNUMBER (優先度は一番低い)
    * 
    * @param op
    *          トークン(数かオペレータ)
    * @return トークンの優先度
    */
   int getPriority(String op)
     {
       final String[] functions = { "+", "-", "/", "*",
           "log", "sqrt" };
       final int[] priority = { 1, 1, 2, 2, 3, 3 };
       for (int i = 0; i < functions.length; i++)
         if (op.equals(functions[i]))
           return priority[i];
       return NUMBER;
     }
   /**
    * tokenStackの先頭からnextPrioより優先度が高い部分を popして計算
    * 
    * @param nextPrio
    *          次に来ているトークンの優先度
    * @param stackPrio
    *          スタックの先頭にあるオペレータの優先度
    * @param tokenStack
    *          トークンが入っているスタック
    * @throws Exception
    */
   void reduce(int nextPrio, int stackPrio,
       Stack<String> tokenStack) throws Exception
     {
       while ((tokenStack.size() > 1)
           && (nextPrio <= stackPrio))
         {
           // 1つめのtoken
           double num1 = Double.parseDouble(tokenStack
               .pop());
           // 2つめのtoken
           String op = tokenStack.pop();
           /** ()の対応用 */
           if (op.equals("("))
             { // 左カッコを発見したら強制的に数式の終わりとみなす
               // 左カッコはここで捨てられる
               tokenStack.push("" + num1);
               return;
             }
           switch (getPriority(op)) {
           case 0:
             throw new Exception("オペレータが足りません");
           case 3: // 関数適用
             if (op.equals("log"))
               num1 = Math.log(num1);
             else if (op.equals("sqrt"))
               num1 = Math.sqrt(num1);
             break;
           case 1:
           case 2: // 四則演算
             if (tokenStack.size() == 0)
               throw new Exception("オペランドが足りません");
             double num2 = Double.parseDouble(tokenStack
                 .pop());
             if (op.equals("/"))
               {
                 if (num1 == 0)
                   throw new Exception("0で割り算しています");
                 num1 = num2 / num1;
               }
             else if (op.equals("*"))
               num1 = num2 * num1;
             else if (op.equals("+"))
               num1 = num2 + num1;
             else if (op.equals("-"))
               num1 = num2 - num1;
             break;
           }
           tokenStack.push("" + num1);
         }
     }
   /**
    * 入力された数式を読んで計算する関数
    * @param st トークンの入力列
    * @return 計算結果
    * @throws Exception
    */
   double parse(StringTokenizer st) throws Exception
     {
       // トークンをためるスタックを初期化
       Stack<String> tokenStack = new Stack<String>();
       int stackTopPrio = 0;
       while (st.hasMoreTokens())
         {
           // 次に処理するトークンを先読み
           String token = st.nextToken();
           /** ()の対応用 */
           if (token.equals(")"))
             // 右カッコが出てきたら、入力文字列の最後とみなす
             break;
           else if (token.equals("("))
             // 左カッコが出てきたら、新しい数式が始まったとみなす
             // その結果を1つの数字とみなす
             tokenStack.push("" + parse(st));
           else
             // 演算か数式
             {
               int nextPrio = getPriority(token);
               // もし先読みしたトークンよりスタックに積んである式のほうが
               // 優先度が高い場合、スタックの中身を先に処理
               if ((nextPrio != NUMBER)
                   && (nextPrio <= stackTopPrio))
                 reduce(nextPrio, stackTopPrio, tokenStack);
               tokenStack.push(token);
               if (nextPrio != NUMBER)
                 stackTopPrio = nextPrio;
             }
         }
       // 入力文字列の最後にきたので、スタックに残っている式を処理
       reduce(0, stackTopPrio, tokenStack);
       if (tokenStack.size() != 1)
         throw new Exception("オペレータが足りません");
       return Double.parseDouble(tokenStack.pop());
     }
   public double parseRPN(StringTokenizer st)
   throws Exception
     {
       Stack<String> tokenStack = new Stack<String>();
       while (st.hasMoreTokens())
         {
           String nextToken = st.nextToken();
           if (nextToken.equals("+"))
             {
               if (tokenStack.size() < 2)
                 throw new Exception("オペランドが足りません");
               double d1 = Double.parseDouble(tokenStack.pop());
               double d2 = Double.parseDouble(tokenStack.pop());
               tokenStack.push("" + (d2 + d1));
             }
           else if (nextToken.equals("-"))
             {
               if (tokenStack.size() < 2)
                 throw new Exception("オペランドが足りません");
               double d1 = Double.parseDouble(tokenStack.pop());
               double d2 = Double.parseDouble(tokenStack.pop());
               tokenStack.push("" + (d2 - d1));
             }
           else if (nextToken.equals("log"))
             {
               if (tokenStack.size() < 1)
                 throw new Exception("オペランドが足りません");
               double d1 = Double.parseDouble(tokenStack.pop());
               tokenStack.push("" + Math.log(d1));
             }
           else 
             tokenStack.push(nextToken);
         }
       //最後にスタックには数字が一つ残っているはず
       if (tokenStack.size() != 1)
         throw new Exception("オペレータが足りません");
       return Double.parseDouble(tokenStack.pop());
     }
   
   public static void main(String[] args)
     {
       try
         {
           BufferedReader br = new BufferedReader(
               new InputStreamReader(System.in));
           while (true)
             {
               System.out.print(">");
               String line = br.readLine();
               if (line == null)
                 break;
               StringTokenizer st = new StringTokenizer(
                   line);
               try
                 {
                   Calculator C = new Calculator();
                   //System.out.println(C.parseRPN(st)); // 逆ポーランド電卓 
                   System.out.println(C.parse(st));    // 普通の電卓
                 }
               catch (Exception e)
                 {
                   System.out.println("Error = " + e);
                 }
             }
         }
       catch (Exception exp)
         {
           exp.printStackTrace();
         }
     }
 }
Personal tools
Namespaces

Variants
Actions
Navigation
metabolites
Toolbox