JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java 程式分享區  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to topicthreaded modego to previous topicgo to next topic
話題被移動
該話題已被移動 - caterpillar , 2004-02-20 21:18
如果您尚不清楚該話題被移動的原因,請參考論壇規則以及本版公告或者聯系本版版主。
本主題所含的標籤
無標籤
作者 [工具]模擬工程計算機的四則運算程式(by Java) [精華]
sungo

瘋狂口罩大盜



發文: 822
積分: 17
於 2004-01-28 19:55 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
程式碼如下,請問各位有沒有執行效率更好的寫法:
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*★Designer:SUNGO-2004.01。★*/
/*★Program:模擬工程用計算機-四則運算處理程式(v1.0)。★*/
/*★Java VM 版本:1.4.2_01-b06。★*/
/*★開發環境:Borland Jbuilder X 企業版。★*/
/*★程式邏輯說明:請拉到最下面↓↓↓★*/
 
import java.text.DecimalFormat;
import javax.swing.*;
import java.util.*;
import java.awt.*; //import:引入程式中所需要使用到的類別;星號*表示包括以下全部。
import java.awt.event.*;
 
public class sungo //類別名稱:sungo (注意:類別名稱需與檔名一致才能編譯!)
    extends JFrame { //繼承自JFrame
  private JLabel prompt; //GUI-文字標籤
  private JTextField input; //GUI-輸入文字方塊
  private JTextArea output; //GUI-輸出文字方塊
 
  public sungo() { //類別名稱:sungo
    super("SUNGO - 模擬工程用計算機<v1.0>"); //★視窗標題所顯示的名稱★
    Container c = getContentPane();
    c.setLayout(new FlowLayout());
    prompt = new JLabel("請輸入運算式,並按【Enter】鍵執行:"); //★標籤文字★
    c.add(prompt);
    input = new JTextField(25); //設定輸入文字方塊的長度
    input.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) { //事件:按下Enter鍵後由此開始執行程式
        String Output_All = "", Output = "", Input = "";
        DecimalFormat preNine = new DecimalFormat("#.#########");
        //宣告了一個DecimalFormat的自訂參考preNine,並以一個DecimalFormat類別的物件初始其值
        //註:("#.#########")此格式的意義為:當浮點變數超過小數點第9位時,自動四捨五入到小數點第9位
        Input = e.getActionCommand(); //由輸入方塊取得字串
        String Input_all = Input;
        int cunter_all = 0; //cunter_all計算陣列索引的位置
        StringTokenizer tokens_all = new StringTokenizer(Input_all); //斷句功能設定宣告(處理tokens_all)
        String m_all[] = new String[Input_all.length() + 1]; //宣告m_all陣列以儲存變數,長度等於輸入字串長度
        while (tokens_all.hasMoreTokens()) {
          m_all[cunter_all] = tokens_all.nextToken("()");
          char charArrayAll[] = m_all[cunter_all].toCharArray(); //將字串轉成字元陣列charArrayAll[]
          int cAll = m_all[cunter_all].length() - 1;
          if (charArrayAll[0] == '+' ||
              charArrayAll[0] == '*' || charArrayAll[0] == '/' ||
              charArrayAll[cAll] == '+' || charArrayAll[cAll] == '-' ||
              charArrayAll[cAll] == '*' || charArrayAll[cAll] == '/'
              ) {
            Output_All += m_all[cunter_all];
          }
          else {
            Output_All += SAll(m_all[cunter_all]);
          }
        }
        String Output1 = "", Output2 = "";
        //Show出截取字元,處理程式區段開始-->
        String Input_show_n = Input;
        String Input_show_m = Input;
        int cunter_show_n = 0, cunter_show_m = 0; //cunter_show_n、cunter_show_m,計算陣列索引的位置
        StringTokenizer tokens_show_n = new StringTokenizer(Input_show_n); //斷句功能設定宣告(處理tokens_show_n)
        StringTokenizer tokens_show_m = new StringTokenizer(Input_show_m); //斷句功能設定宣告(處理tokens_show_m)
        double n_show[] = new double[Input_show_n.length() + 1]; //宣告n_show陣列以儲存變數,長度等於輸入字串長度
        String m_show[] = new String[Input_show_m.length() + 1]; //宣告m_show陣列以儲存變數,m_show[]=字串變數
        while (tokens_show_n.hasMoreTokens()) {
          n_show[cunter_show_n] = Double.parseDouble(tokens_show_n.nextToken(
              "(-/+*)"));
          Output1 += "【" + preNine.format(n_show[cunter_show_n]) + "】"; //"取出所有數字"的字串輸出
          cunter_show_n++;
        }
        while (tokens_show_m.hasMoreTokens()) {
          m_show[cunter_show_m] = tokens_show_m.nextToken("()0123456789.");
          Output2 += "『" + m_show[cunter_show_m] + "』";
          cunter_show_m++;
        }
        //Show出截取字元處理,程式區段結束-->
        Output = SAll(Output_All); //真正的四則運算結果,SAll=副程式
        output.setText("數字鍵:" + Output1 + "\n符號鍵:" + Output2 + "\n☆答案☆:" +
                       Output); //將結果輸出於文字方塊上
      }
    } //對應input.addActionListener(new ActionListener()
    ); //對應input.addActionListener
    c.add(input);
    output = new JTextArea(5, 25); //輸出方塊的大小設定
    output.setEditable(false);
    c.add(new JScrollPane(output));
    setSize(320, 203); //面版大小設定
    show();
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  } //對應public sungo()
 
//副程式:SSubToAdd(String SubToAdd)--用途:負負取正
  public static String SSubToAdd(String SubToAdd) {
    StringBuffer buf7 = new StringBuffer(SubToAdd); //宣告SringBuffer類別來處理字串
    String S7 = "";
    char charArray7[] = SubToAdd.toCharArray(); //將字串轉成字元陣列charArray[]
    int x7 = 0;
    for (int j7 = 0; j7 < SubToAdd.length(); ++j7) {
      if (charArray7[j7] == '-' && charArray7[j7 + 1] == '-') {
        buf7.insert(j7 + x7, '+'); //意義:將--變為+
        buf7.deleteCharAt(j7 + x7 + 1);
        buf7.deleteCharAt(j7 + x7 + 1);
        --x7;
      }
    }
    S7 = buf7.toString();
    return S7;
  }
 
//副程式:SAll(String Input2)--用途:計算字串型態的四則運算(不包括括號)
  public static String SAll(String Input2) {
    DecimalFormat preNine = new DecimalFormat("#.#########");
    String Input_add = ChangeAddStr(Input2); //使用副程式ChangeAddStr
    int cunter_add = 0; //cunter計算陣列索引的位置
    StringTokenizer tokens_add = new StringTokenizer(Input_add); //斷句功能設定宣告(處理Input_add)
    String m_add[] = new String[Input_add.length() + 1]; //宣告m_add陣列以儲存變數,m_add[]=字串變數
    while (tokens_add.hasMoreTokens()) {
      m_add[cunter_add] = tokens_add.nextToken("+");
      cunter_add++;
    }
    double n_add[] = new double[cunter_add + 1]; //宣告n_add陣列以儲存變數,n[]=浮點變數
    for (int z = 0; z < cunter_add; ++z) {
      n_add[z] += Double.parseDouble(SMulDiv(m_add[z]));
    }
    for (int f = 0; f < cunter_add; ++f) {
      n_add[f + 1] += n_add[f];
    }
    return preNine.format(n_add[cunter_add - 1]); //傳回計算結果(字串型態)
  }
 
//副程式:SMulDiv(String Input)--用途:將字串乘法與除法轉換成實際運算
  public static String SMulDiv(String Input) {
    double Result = 0; //Result=最後結果
    DecimalFormat preNine = new DecimalFormat("#.#########");
    if (Input.indexOf('*') != -1 || Input.indexOf('/') != -1) {
      String Input_n = ChangeStr(Input, '-', '+'); //處理Input取變數的負號情況
      String Input_m = DeleteStrHead(Input); //處理Input取運算元的負號情況
      int cunter_n = 0, cunter_m = 0; //cunter計算陣列索引的位置
      double n[] = new double[Input_n.length() + 1]; //宣告n陣列以儲存變數,n[]=Double變數
      String m[] = new String[Input_m.length() + 1]; //宣告m陣列以儲存變數,n[]=字串變數
      StringTokenizer tokens_n = new StringTokenizer(Input_n); //斷句功能設定宣告(處理Input_n)
      StringTokenizer tokens_m = new StringTokenizer(Input_m); //斷句功能設定宣告(處理Input_m)
      while (tokens_n.hasMoreTokens()) {
        n[cunter_n] = Double.parseDouble(tokens_n.nextToken("+/*"));
        n[cunter_n] = n[cunter_n];
        cunter_n++; //此時的cunter_n=所有變數的個數,如為4則表示有n[0~3],4個要處理的數字
      }
      while (tokens_m.hasMoreTokens()) {
        m[cunter_m] = String.valueOf(tokens_m.nextToken("0123456789."));
        if (m[cunter_m].equals("*+")) {
          m[cunter_m] = "*"; //將負數乘法所造成的截取誤差更正,以取得正確運算元
        }
        if (m[cunter_m].equals("/+")) {
          m[cunter_m] = "/"; //將負數除法所造成的截取誤差更正,以取得正確運算元
        }
        cunter_m++;
      } //此時的cunter_m=運算元的總數,如為3則表示有m[0~2],3個加減乘除符號
      //運算處理開始-->
      for (int i = 0; i < cunter_m; ++i) {
        if (m[i].equals("*")) {
          n[i + 1] *= n[i];
        }
        else {
          if (m[i].equals("/")) {
            n[i + 1] = n[i] / n[i + 1];
          }
        }
      }
      Result = n[cunter_n - 1]; //運算處理結束<--
    }
    else {
      Result = Double.parseDouble(Input);
    }
    return preNine.format(Result); //傳回計算結果(字串型態)
  }
 
//副程式:ChangeStr(S1=要處理的字串,chOld=要判斷的字元,chAdd=要加上去的字元)
  public static String ChangeStr(String S1, char chOld, char chAdd) {
    StringBuffer buf1 = new StringBuffer(S1); //宣告SringBuffer類別來處理字串
    String S2 = "";
    char charArray1[] = S1.toCharArray(); //將字串轉成字元陣列charArray[]
    int x1 = 0;
    for (int i1 = 0; i1 < S1.length(); i1++) {
      if (charArray1[i1] == chOld) {
        buf1.insert(i1 + x1, chAdd); //意義:如果字串內有'chOld',就在前面前加上'chAdd'
        ++x1;
      }
    }
    S2 = String.valueOf(buf1); //將Buf轉成String型態存入Input
    return S2;
  }
 
//副程式:DeleteStrHead(S3=要處理的字串)--用途:假如開頭是'-'則刪除它
  public static String DeleteStrHead(String S3) {
    StringBuffer buf2 = new StringBuffer(S3); //宣告SringBuffer類別來處理字串
    String S4 = "";
    char charArray2[] = S3.toCharArray(); //將字串轉成字元陣列
    if (charArray2[0] == '-') {
      buf2.delete(0, 1);
    }
    S4 = buf2.toString(); //將Buf轉成String型態存入Input
    S4 = S4.replace('-', '+'); //將字串內所有的'-'用'+'取代
    return S4;
  }
 
//副程式:ChangeAddStr(S5=要處理的字串)
  public static String ChangeAddStr(String S5) {
    S5 = SSubToAdd(S5);
    StringBuffer buf3 = new StringBuffer(S5); //宣告SringBuffer類別來處理字串
    String S6 = "";
    char charArray3[] = S5.toCharArray(); //將字串轉成字元陣列charArray[]
    int x3 = 0;
    for (int i3 = 0; i3 < S5.length(); i3++) {
      if (charArray3[i3] == '-') {
        buf3.insert(i3 + x3, '+'); //意義:如果字串內有'-',就在前面前加上'+'
        ++x3;
      }
    }
    StringBuffer buf4 = new StringBuffer(buf3.toString()); //宣告SringBuffer類別來處理字串
    char charArray4[] = buf4.toString().toCharArray(); //將字串轉成字元陣列charArray[]
    int f = 0;
    for (int j3 = 0; j3 < buf4.toString().length(); j3++) {
      if (charArray4[j3] == '*' && charArray4[j3 + 1] == '+') {
        buf4.deleteCharAt(j3 + f + 1); //意義:將*+變為*
        --f;
      }
      if (charArray4[j3] == '/' && charArray4[j3 + 1] == '+') {
        buf4.deleteCharAt(j3 + f + 1); //意義:將*/變為*
        --f;
      }
    }
    S6 = String.valueOf(buf4); //將Buf轉成String型態存入S6
    return S6;
  }
 
//主程式main
  public static void main(String args[]) {
    sungo app = new sungo(); //類別名稱:sungo
    app.addWindowListener(
        new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0); //按下視窗關關閉鈕後,程式結束
      }
    }
    );
  }
 
  private void jbInit() throws Exception {
    prompt.setFont(new java.awt.Font("新細明體", 0, 15)); //文字標籤字體設定
    prompt.setForeground(new Color(255, 255, 255)); //文字標籤字型顏色
    input.setBackground(new Color(235, 255, 235)); //輸入方塊背景色
    input.setForeground(new Color(0, 102, 255)); //輸入方塊字型顏色
    output.setBackground(new Color(235, 255, 235)); //輸出方塊背景色
    output.setForeground(new Color(0, 102, 255)); //輸出方塊字型顏色
    this.getContentPane().setBackground(new Color(204, 102, 255)); //★面版底色設定★
    this.setDefaultCloseOperation(HIDE_ON_CLOSE); //隱藏視窗最大化的按鈕
    this.setResizable(false); //改變視窗大小禁能(Disable)
  }
}
 
//㊣程式邏輯說明㊣:
/*
   此程式最主要的觀念,就是字串上的處理。使用者輸入的運算式,妳必須讓程式像人類在作四則運算一
 樣,把結果算出來。也就是要符合先乘除後加減 ,以及括號()優先處理的原則。假如使用者輸入了:
 (0.8+0.7)*(12-2),妳的一步驟就是先處理0.8+0.7以及-12+2,最後把2個結果乘起來,就是答案

   程式的作法:利用StringTokenizer類別將字串做有意義的分斷。將可取得0.8、0.7、12、『-2』
 四個數字,以及+、*、『+』的運算元。在這裡提供一個觀念:減法就是等於被加數+負加數,例如:5-2
 就是等於 5+(-2),有這個觀念妳就可以瞭解,為何取出來的數字是『-2』而運算元是『+』,這樣的作
 法就是為了更方便程式的計算!再來只要設計一些邏輯,判斷執行的順序後,即可算出答案!現在就以
 (0.8+0.7)*(12-2)這個運算式來說明它在程式中是如何執行計算的。

 1.判別括號的斷句程序會把它先作下列的分斷:
 0.8+0.7
 *
 12-2

 2.將這3個斷句送入自製副程式SAll()計算。SAll副程式可以計算不含括號的四則運算!要執行SAll時
 ,必須先判別輸入的是不是有效的運算式。所以要在此之前寫一個判斷邏輯,非有效計算暫時不處理,例n 如本運算式斷句*的部分,只有一個運算元前後並無數字可作運算,它即是一個非有效計算。 經過此道順
 序後,得到新字串:1.5*10。

 3.最後只要把作完括號處理的新字串1.5*10再送入SAll()計算,即可得到15這個正確答案。

 */

PS:附加檔是編譯好的exe檔,可在裝有JRE的Windows直接執行。

sungo.exe (98.3k)


sungo edited on 2007-07-13 23:33
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
liminjun

JavaDOCHelper真讚



發文: 496
積分: 5
於 2004-01-28 21:00 user profilesend a private message to usersend email to liminjunreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Post is deleted

caterpillar edited on 2004-02-21 14:58
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
browser

戀香

版主

發文: 3570
積分: 1
於 2004-01-28 22:10 user profilesend a private message to usersend email to browserreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Post is deleted

caterpillar edited on 2004-02-21 15:02
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2004-01-28 23:03 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Post is deleted

caterpillar edited on 2004-02-21 15:03
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
caterpillar

良葛格

版主

發文: 2587
積分: 70
於 2004-01-29 00:39 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
四則運算可以先將中序式轉為後序式,然後再由後序式進行運算。。。。

參考一下:
中序式轉後序式:http://openhome.cc/Gossip/AlgorithmGossip/InFixPostfix.htm
後序式的運算:http://openhome.cc/Gossip/AlgorithmGossip/PostfixCal.htm

PS. 這個程式倒讓我想到大學時,數值方法曾寫過一個解兩階微分方程的程式,已經可以解一個小電路問題了,同學說若相同觀念解到五階微分方程,加上圖形化介面,就可以完成一個小型的matlab了。。。。當時是用VB4寫的,還可以畫一個解的曲線,蠻好玩的。。。。


caterpillar edited on 2013-04-06 16:47
reply to postreply to post
良葛格學習筆記
CodeData 專欄
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
T55555

Java, Ruby, Haskell

版主

發文: 1006
積分: 24
於 2004-01-29 01:20 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Wow...
If I am writing this application, I will not try parse by myself.
I will use javacc or antlr tools to do lex/yacc stuff.
And the application will be very "short".
( need an example ? )


reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:T55555]
sungo

瘋狂口罩大盜



發文: 822
積分: 17
於 2004-01-29 01:29 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
T55555 wrote:
Wow...
If I am writing this application, I will not try parse by myself.
I will use javacc or antlr tools to do lex/yacc stuff.
And the application will be very "short".
( need an example ? )


嗯嗯!請這位朋友示範一下作法!規定的介面是:Application。(老師說的=.=)


sungo edited on 2004-01-29 01:49
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
T55555

Java, Ruby, Haskell

版主

發文: 1006
積分: 24
於 2004-01-29 03:46 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
First make sure you can use third party library.
If no, ignore anything below.

Then go to www.antlr.org download the antlr library.

Here is a "quick" example:

Grammar File:
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
class CalcParser extends Parser;
 
expr returns [double value = 0.0]
{double x;}
  :  value=mexpr
     ( PLUS  x=mexpr  {value += x;}
     | MINUS x=mexpr  {value -= x;}
     )* 
  ;
 
mexpr returns [double value=0.0]
{double x;}
  :  value=atom 
     ( MULTI  x=atom  {value *= x;}
     | DIVIDE x=atom  {value /= x;} 
     )*
  ;
 
atom returns [double value=0.0]
{double x;}
  :  d:DOUBLE {value=Double.parseDouble(d.getText());}
  |  LPAREN value=expr RPAREN
  |  PLUS  x=atom {value = x;}
  |  MINUS x=atom {value = -x;}
  ;
 
class CalcLexer extends Lexer;
 
LPAREN : '(' ;
RPAREN : ')' ;
PLUS   : '+' ;
MINUS  : '-' ;
MULTI  : '*' ;
DIVIDE : '/' ;
WS     : (' ' | '\t' | '\n' | '\r') {$setType(Token.SKIP);} ;
DOUBLE : ('0'..'9')+ ('.' ('0'..'9')+)? ;


Then the main class file:
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
import antlr.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
 
public class Calculator extends JFrame {
  public static void main(String[] args) {
    new Calculator();
  }
 
  JTextField m_input = new JTextField();
  JLabel m_output = new JLabel("Enter Math Expression and <ENTER>");
 
  public Calculator() {
    super("Calculator v0.1");
 
    JPanel p = new JPanel(new GridLayout(0, 1, 5, 5));
    p.add(m_input);
    p.add(m_output);
    m_input.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        try {
          Reader input = new StringReader(m_input.getText());
          CalcLexer lexer = new CalcLexer(input);
          CalcParser parser = new CalcParser(lexer);
          double result = parser.expr();
          m_output.setText(Double.toString(result));
        } 
        catch (Exception ex) { 
          ex.printStackTrace();
        }
      }
    });
 
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setContentPane(p);
    pack();
    setLocationRelativeTo(null);
    setVisible(true);
  }
  
}


Of course this is very basic (and quick demo), the application do not check:
divide 0 (infinity)
0 divide 0 (not a value)
and the double value do not check the science expression like -2.5e-3
(BTW: it is easy to add these features.)

Longtime ago, I did try write a "big" parser by "hand", after had that exprerience, no more write lex/yacc stuff by hand ...

Here is the result:


T55555 edited on 2004-01-29 03:57
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:T55555]
sungo

瘋狂口罩大盜



發文: 822
積分: 17
於 2004-01-29 05:36 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
T55555 wrote:
First make sure you can use third party library.
If no, ignore anything below.

Then go to www.antlr.org download the antlr library.

Here is a "quick" example:

Grammar File:
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
class CalcParser extends Parser;
 
expr returns [double value = 0.0]
{double x;}
  :  value=mexpr
     ( PLUS  x=mexpr  {value += x;}
     | MINUS x=mexpr  {value -= x;}
     )* 
  ;
 
mexpr returns [double value=0.0]
{double x;}
  :  value=atom 
     ( MULTI  x=atom  {value *= x;}
     | DIVIDE x=atom  {value /= x;} 
     )*
  ;
 
atom returns [double value=0.0]
{double x;}
  :  d:DOUBLE {value=Double.parseDouble(d.getText());}
  |  LPAREN value=expr RPAREN
  |  PLUS  x=atom {value = x;}
  |  MINUS x=atom {value = -x;}
  ;
 
class CalcLexer extends Lexer;
 
LPAREN : '(' ;
RPAREN : ')' ;
PLUS   : '+' ;
MINUS  : '-' ;
MULTI  : '*' ;
DIVIDE : '/' ;
WS     : (' ' | '\t' | '\n' | '\r') {$setType(Token.SKIP);} ;
DOUBLE : ('0'..'9')+ ('.' ('0'..'9')+)? ;


Then the main class file:
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
import antlr.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
 
public class Calculator extends JFrame {
  public static void main(String[] args) {
    new Calculator();
  }
 
  JTextField m_input = new JTextField();
  JLabel m_output = new JLabel("Enter Math Expression and <ENTER>");
 
  public Calculator() {
    super("Calculator v0.1");
 
    JPanel p = new JPanel(new GridLayout(0, 1, 5, 5));
    p.add(m_input);
    p.add(m_output);
    m_input.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        try {
          Reader input = new StringReader(m_input.getText());
          CalcLexer lexer = new CalcLexer(input);
          CalcParser parser = new CalcParser(lexer);
          double result = parser.expr();
          m_output.setText(Double.toString(result));
        } 
        catch (Exception ex) { 
          ex.printStackTrace();
        }
      }
    });
 
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setContentPane(p);
    pack();
    setLocationRelativeTo(null);
    setVisible(true);
  }
  
}


Of course this is very basic (and quick demo), the application do not check:
divide 0 (infinity)
0 divide 0 (not a value)
and the double value do not check the science expression like -2.5e-3
(BTW: it is easy to add these features.)

Longtime ago, I did try write a "big" parser by "hand", after had that exprerience, no more write lex/yacc stuff by hand ...

Here is the result:


感謝T55555的示範!您在主程式引入import antlr.*;
請問"antlr"這是一個人家寫好的套件嗎?因為它好像
不是Java裡的類別。假設這個程式純粹只用JDK裡提
供的類別寫的話,caterpillar兄提供的方法:中序式轉
換為後序式後再加上堆疊,我想用這個方法也可以使
程式碼比我原來撰寫的短很多。非常感謝這位朋友示
範^^


browser edited on 2004-01-29 05:36
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
liminjun

JavaDOCHelper真讚



發文: 496
積分: 5
於 2004-01-29 13:57 user profilesend a private message to usersend email to liminjunreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
沒想到我想到的方法和您居然這麼相近(幾乎可以說是一樣)以下開始簡稱為第一種方法
所以我重新開始思考新的一種,嚐試使用另一種方法來寫作這樣子的程式,雖然目前還有一些小bug(某些運算式算不出來),不過整體的效率比起原先快滿多的,外加可以運算超大數字,平均速度約在0~16 ms,至於我和你相同的那個運算方法平均約在 75 ms

(((22*55559999999999988888888797777777777799999999999999955589)-4.44454643+3454564646)*60/(588888880+5))

result : 124538264973365875861849919389574939414928845193278.2111449994971703363020682585985639718773
Time : 15

底下有附您的程式,裡面只有增加計算時間的運算式3行,其他地方皆沒有修改,老實說...真沒想到我和你的想法這麼相近,運算方法可以說是一樣Tounge,所以才想說重新想一種

1
2
3
4
5
6
input.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
  long startTime = System.currentTimeMillis();  ........
  ........
  long endTime = System.currentTimeMillis();
  System.out.println( "Time : " + String.valueOf(endTime-startTime) );


然後附上小弟我重新寫的架構,因為整體思維上改變滿多的,而且第一次用這樣子去想,所以還有些bug有待大家幫忙抓出來修改 Embaressed 題目是 高效率的大數運算

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import java.io.*;
import java.util.*;
import java.util.regex.*;
import java.math.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Test extends JFrame
{
 
    public Test(){
        final JLabel jlb = new JLabel( "請輸入目錄位置" );
        jlb.setBounds(5 , 5 , 300 ,30);
 
        final JTextField jtf = new JTextField();
        jtf.setBounds(5 , 30 ,300 ,20);
 
        final JButton jbn = new JButton( "確定" );
        jbn.setBounds( 320 ,5 , 70 ,60);
 
        Container cp = this.getContentPane();
        cp.setLayout( null );
        cp.add( jlb );
        cp.add( jtf );
        cp.add( jbn );
 
        jbn.addActionListener( new ActionListener(){
            public void actionPerformed( ActionEvent e ){
                if(e.getSource() == jbn ){
                    long startTime = System.currentTimeMillis();
                    go( jtf.getText() );
                    long endTime = System.currentTimeMillis();
                    System.out.println( "Time : " + String.valueOf(endTime-startTime) );
 
                }
            }
        });
 
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                dispose();
                System.exit(0);
            }
        });
    }
 
    public static void main(String[] args){
 
        Test ts = new Test();
 
        ts.setSize(400, 100);
        ts.setTitle("Test");
        ts.setVisible(true);
 
        //((12.3+3-(45-67)+89)*60/(50+5));
 
    }
 
    public void go( String operation ){
        try{
 
            String result = Operation( operation );
            System.out.println( "result : " + result );
 
        }catch( Exception e ){
            System.err.println( "Error : " + e  );
        }
    }
 
    public String Operation( String operation_temp ){
 
            Pattern pattern = Pattern.compile( "\\-\\-" );
            Matcher m = pattern.matcher(operation_temp);
            String temp = m.replaceAll("+");
 
            pattern = Pattern.compile( "\\+\\-" );
            m = pattern.matcher(temp);
            temp =m.replaceAll("-");
 
            pattern = Pattern.compile( "\\-\\+" );
            m = pattern.matcher(temp);
            temp =m.replaceAll("-");
 
            pattern = Pattern.compile( "\\([0-9\\+\\-\\*\\/\\.]*\\)" );
            m = pattern.matcher(operation_temp);
            StringBuffer sb = new StringBuffer();
 
            while (  m.find() ) {
                 System.out.println( "group : " + m.group() );
                 m.appendReplacement(sb, Arithmetic(m.group()) );
 
            }
            m.appendTail(sb);
 
            if(  (sb.toString().indexOf("(") != -1 ) &&
                 (sb.toString().indexOf(")") != -1 )){
 
                 return Operation( sb.toString() );
 
            }else{
                return Arithmetic(sb.toString());
            }
 
    }
 
    public String Arithmetic( String arithmetic ){
        LinkedList op_stack = new LinkedList();
        LinkedList str_stack = new LinkedList();
        int op_index = 0;
        int str_index_start = 0;
        int str_index_end = 0;
        //===========================================================
 
        Pattern pattern = Pattern.compile( "\\-\\-" );
        Matcher m = pattern.matcher(arithmetic);
        String temp = m.replaceAll("+");
 
        pattern = Pattern.compile( "\\+\\-" );
        m = pattern.matcher(temp);
        temp =m.replaceAll("-");
 
        pattern = Pattern.compile( "\\-\\+" );
        m = pattern.matcher(temp);
        temp =m.replaceAll("-");
        //===========================================================
        pattern = Pattern.compile( "[\\+\\-\\*\\/]" );
        m = pattern.matcher(temp);
        while( m.find() ) {op_stack.add( m.group() );}
        //===========================================================
        pattern = Pattern.compile( "[^\\+\\-\\*\\/\\(\\)]+" );
        m = pattern.matcher(temp);
        while( m.find() ) {str_stack.add( m.group() );}
        //===========================================================
        while( op_stack.size() > 0 ){
 
            if( (op_index = op_stack.indexOf("*")) != -1){
                String temp1 = (String)str_stack.get(op_index);
                String temp2 = (String)str_stack.get(op_index+1);
                String op = (String)op_stack.get(op_index);
                op_stack.remove(op_index);
 
                System.out.println(  temp1 + op + temp2);
 
                BigDecimal value1 = new  BigDecimal(temp1);
                BigDecimal value2 = new  BigDecimal(temp2);
 
                String result = value1.multiply( value2 ).toString();
 
                str_stack.remove(op_index);
                str_stack.remove(op_index);
                str_stack.add(op_index , result);
 
            }else if( (op_index = op_stack.indexOf("/")) != -1){
                String temp1 = (String)str_stack.get(op_index);
                String temp2 = (String)str_stack.get(op_index+1);
                String op = (String)op_stack.get(op_index);
                op_stack.remove(op_index);
 
                System.out.println(  temp1 + op + temp2);
 
                BigDecimal value1 = new  BigDecimal(temp1);
                BigDecimal value2 = new  BigDecimal(temp2);
 
                String result = value1.divide(value2 , 20 , BigDecimal.ROUND_HALF_UP).toString();
 
                str_stack.remove(op_index);
                str_stack.remove(op_index);
                str_stack.add(op_index , result);
            }else{
                  String temp1 = (String)str_stack.getFirst();
                  str_stack.removeFirst();
                  String temp2 = (String)str_stack.getFirst();
                  str_stack.removeFirst();
                  String op = (String)op_stack.getFirst();
                  op_stack.removeFirst();
 
                  System.out.println( temp1 + op + temp2);
 
                  BigDecimal value1 = new  BigDecimal(temp1);
                  BigDecimal value2 = new  BigDecimal(temp2);
                  String result = "";
                  if( op.equals( "+" ) ){
                      result = value1.add(value2).toString();
                  }else if( op.equals( "-" ) ){
                      result = value1.subtract(value2).toString();
                  }
                  str_stack.addFirst( result );
            }
 
        }
 
        return (String)str_stack.getFirst();
    }
}


Temp.rar (6.17k)


liminjun edited on 2004-01-29 14:40
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:T55555]
popcorny

Jakarta 2%

版主

發文: 752
積分: 20
於 2004-01-29 18:12 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
T55555 wrote:
[訴刪]


推這篇...
放在Open Source版我覺得很適合
簡單明瞭的展現ANTLR的寫法..Big Smile
不過可能不太適合初學者...
這個可能要修過compiler的人才會用吧... Disapproved
初學者還是用較土法煉鋼的方法比較適合... Tongue


reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:liminjun]
sungo

瘋狂口罩大盜



發文: 822
積分: 17
於 2004-01-29 18:54 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
liminjun wrote:
沒想到我想到的方法和您居然這麼相近(幾乎可以說是一樣)以下開始簡稱為第一種方法
所以我重新開始思考新的一種,嚐試使用另一種方法來寫作這樣子的程式,雖然目前還有一些小bug(某些運算式算不出來),不過整體的效率比起原先快滿多的,外加可以運算超大數字,平均速度約在0~16 ms,至於我和你相同的那個運算方法平均約在 75 ms

(((22*55559999999999988888888797777777777799999999999999955589)-4.44454643+3454564646)*60/(588888880+5))

result : 124538264973365875861849919389574939414928845193278.2111449994971703363020682585985639718773
Time : 15

底下有附您的程式,裡面只有增加計算時間的運算式3行,其他地方皆沒有修改,老實說...真沒想到我和你的想法這麼相近,運算方法可以說是一樣Tounge,所以才想說重新想一種

1
2
3
4
5
6
input.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
  long startTime = System.currentTimeMillis();  ........
  ........
  long endTime = System.currentTimeMillis();
  System.out.println( "Time : " + String.valueOf(endTime-startTime) );


然後附上小弟我重新寫的架構,因為整體思維上改變滿多的,而且第一次用這樣子去想,所以還有些bug有待大家幫忙抓出來修改 Embaressed 題目是 高效率的大數運算


ㄎㄎ!剛剛跑了一下您寫的跟我寫的程式,的確比我原來的程式跑得快很多!
PS:同樣是執行:(((22*555599999999999888888887977777777777999
99999999999955589)-4.44454643+3454564646)*60/(588888880+5))。

當初只想趕快把程式趕快作好,好趕快交差∼根本沒有想到運算效率的問題∼
因為裡面用了太多Array以及BufferString,假如拿這個程式去執行超大量
計算,可能會Delay到死吧=.=

看到liminjun兄用currentTimeMillis()來計算執行時間,不禁讓我想起C++的
clock()..Java的currentTimeMillis()就等於C++的clock()..

PS:附一下執行的比較圖:(Time的單位:ms)


sungo edited on 2004-01-29 19:01
reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
T55555

Java, Ruby, Haskell

版主

發文: 1006
積分: 24
於 2004-02-22 07:21 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Wow ...
Unfair! Smile My short program no point ? (even up by popcorny) Disapproved

Anyway, I will try to post a calculator program by using JavaCC and Antlr.
(and maybe post on open source section Smile )


reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:T55555]
caterpillar

良葛格

版主

發文: 2587
積分: 70
於 2004-02-22 10:58 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
T55555 wrote:
Wow ...
Unfair! Smile My short program no point ? (even up by popcorny) Disapproved

Anyway, I will try to post a calculator program by using JavaCC and Antlr.
(and maybe post on open source section Smile )


Sorry!轉移話題過來後,主要針對第一個發表分享程式的作者推薦,算是鼓勵大家分享程式,而之後的討論串中是否有推薦,則以保留該話題在原版面中是否被推薦,所以並沒有針對您的部份進行推薦,並不是說您的程式分享不好。

看了一下,您的回應文章是不錯的,期待您將該篇文章再擴充為一個更完整的程式與大家分享。


reply to postreply to post
良葛格學習筆記
CodeData 專欄
作者 Re:[工具]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
大豬公

Big Pig



發文: 20
積分: 0
於 2004-04-03 04:34 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
一般來講,有學過資料結構的,這個case都會用中序式轉
後序式來作!sungo跟liminjun的解法卻是另一種不同方向
的思考∼∼這正是邏輯有趣的地方。Smile


reply to postreply to post
豬的習性:好奇而膽小、愛乾淨、會在固定地方大小便、喜群居,唯公豬好打鬥。
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:T55555]
HD





發文: 11
積分: 0
於 2005-10-17 21:22 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
我找到一個Bug
Test.java這個檔案
會先去作乘才會去作除
例如6/2*3
他會先作2*3
而不是先作6/2
在 Arithmetic這個function裡似乎要作一點判斷才行
我先想一下


reply to postreply to post
作者 Re:[工具]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
HD





發文: 11
積分: 0
於 2005-10-17 23:32 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list

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
            if( (op_index = op_stack.indexOf("*")) != -1){
                String temp1 = (String)str_stack.get(op_index);
                String temp2 = (String)str_stack.get(op_index+1);
                String op = (String)op_stack.get(op_index);
                op_stack.remove(op_index);
 
                System.out.println(  temp1 + op + temp2);
 
                BigDecimal value1 = new  BigDecimal(temp1);
                BigDecimal value2 = new  BigDecimal(temp2);
 
                String result = value1.multiply( value2 ).toString();
 
                str_stack.remove(op_index);
                str_stack.remove(op_index);
                str_stack.add(op_index , result);
 
            }else if( (op_index = op_stack.indexOf("/")) != -1){
                String temp1 = (String)str_stack.get(op_index);
                String temp2 = (String)str_stack.get(op_index+1);
                String op = (String)op_stack.get(op_index);
                op_stack.remove(op_index);
 
                System.out.println(  temp1 + op + temp2);
 
                BigDecimal value1 = new  BigDecimal(temp1);
                BigDecimal value2 = new  BigDecimal(temp2);
 
                String result = value1.divide(value2 , 20 , BigDecimal.ROUND_HALF_UP).toString();
 
                str_stack.remove(op_index);
                str_stack.remove(op_index);
                str_stack.add(op_index , result);
            }

改成
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
if( (op_index =op_stack.indexOf("*"))!= -1  || (op_index =op_stack.indexOf("/")) != -1 ){             
                 
         if( (op_stack.indexOf("*"))!= -1  && (op_stack.indexOf("/")) != -1 ){           
           if(op_stack.indexOf("*")>op_stack.indexOf("/")){
             op_index = op_stack.indexOf("/");           
           }else{
             op_index = op_stack.indexOf("*"); 
           }       
                }                    
                                                  
                                                                  
                String temp1 = (String)str_stack.get(op_index);
                String temp2 = (String)str_stack.get(op_index+1);
                String op = (String)op_stack.get(op_index);
                op_stack.remove(op_index);
 
                System.out.println(  temp1 + op + temp2);
 
                BigDecimal value1 = new  BigDecimal(temp1);
                BigDecimal value2 = new  BigDecimal(temp2);
                
                String result="";
                if(op.equals( "/" )){
                  result = value1.divide(value2 , 20 , BigDecimal.ROUND_HALF_UP).toString();
                }else if(op.equals( "*" )){
                  result = value1.multiply( value2 ).toString();                  
                }                                           
 
                str_stack.remove(op_index);
                str_stack.remove(op_index);
                str_stack.add(op_index , result);
 
            }
 

就可修正了


reply to postreply to post
作者 Re:[工具]模擬工程計算機的四則運算程式(by Java) [Re:sungo]
qwewsw





發文: 3
積分: 0
於 2010-06-23 10:26 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
請大大幫忙一下~

這程式是由鍵盤KEY算式式子

如何改成以按鈕式KEY式子

就像小算盤那樣方式輸入運算式子


reply to postreply to post
作者 Re:[分享]模擬工程計算機的四則運算程式(by Java) [Re:caterpillar]
chuchu0317





發文: 53
積分: 0
於 2010-10-19 15:49 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
如果四則運算中包含"小數點"和"%"
請問應該怎麼處理?
謝謝!!


reply to postreply to post
» JWorld@TW »  Java 程式分享區

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8