KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jrobin > core > RpnCalculator


1 /* ============================================================
2  * JRobin : Pure java implementation of RRDTool's functionality
3  * ============================================================
4  *
5  * Project Info: http://www.jrobin.org
6  * Project Lead: Sasa Markovic (saxon@jrobin.org);
7  *
8  * (C) Copyright 2003, by Sasa Markovic.
9  *
10  * Developers: Sasa Markovic (saxon@jrobin.org)
11  * Arne Vandamme (cobralord@jrobin.org)
12  *
13  * This library is free software; you can redistribute it and/or modify it under the terms
14  * of the GNU Lesser General Public License as published by the Free Software Foundation;
15  * either version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  * See the GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License along with this
22  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */

25
26 package org.jrobin.core;
27
28 import java.util.StringTokenizer JavaDoc;
29
30 class RpnCalculator {
31     static final String JavaDoc VAR_PLACEHOLDER = "value";
32
33     private static final byte TOK_VAR = 0;
34     private static final byte TOK_NUM = 1;
35     private static final byte TOK_PLUS = 2;
36     private static final byte TOK_MINUS = 3;
37     private static final byte TOK_MULT = 4;
38     private static final byte TOK_DIV = 5;
39     private static final byte TOK_MOD = 6;
40     private static final byte TOK_SIN = 7;
41     private static final byte TOK_COS = 8;
42     private static final byte TOK_LOG = 9;
43     private static final byte TOK_EXP = 10;
44     private static final byte TOK_FLOOR = 11;
45     private static final byte TOK_CEIL = 12;
46     private static final byte TOK_ROUND = 13;
47     private static final byte TOK_POW = 14;
48     private static final byte TOK_ABS = 15;
49     private static final byte TOK_SQRT = 16;
50     private static final byte TOK_RANDOM = 17;
51     private static final byte TOK_LT = 18;
52     private static final byte TOK_LE = 19;
53     private static final byte TOK_GT = 20;
54     private static final byte TOK_GE = 21;
55     private static final byte TOK_EQ = 22;
56     private static final byte TOK_IF = 23;
57     private static final byte TOK_MIN = 24;
58     private static final byte TOK_MAX = 25;
59     private static final byte TOK_LIMIT = 26;
60     private static final byte TOK_DUP = 27;
61     private static final byte TOK_EXC = 28;
62     private static final byte TOK_POP = 29;
63     private static final byte TOK_UN = 30;
64     private static final byte TOK_UNKN = 31;
65     // private static final byte TOK_NOW = 32;
66
// private static final byte TOK_TIME = 33;
67
private static final byte TOK_PI = 34;
68     private static final byte TOK_E = 35;
69     private static final byte TOK_AND = 36;
70     private static final byte TOK_OR = 37;
71     private static final byte TOK_XOR = 38;
72
73     private String JavaDoc[] tokens;
74     private byte[] tokenCodes;
75     private double[] parsedDoubles;
76     private RpnStack stack = new RpnStack();
77
78     private String JavaDoc rpnExpression;
79     private double value;
80     // private long timestamp;
81

82     RpnCalculator(String JavaDoc rpnExpression) throws RrdException {
83         this.rpnExpression = rpnExpression;
84         createTokens();
85     }
86
87     void setValue(double value) {
88         this.value = value;
89     }
90
91     /* not supported yet
92     public void setTimestamp(long timestamp) {
93         this.timestamp = timestamp;
94     }
95     */

96
97     private void createTokens() throws RrdException {
98         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(rpnExpression, ",");
99         int count = st.countTokens();
100         tokens = new String JavaDoc[count];
101         tokenCodes = new byte[count];
102         parsedDoubles = new double[count];
103         for(int i = 0; st.hasMoreTokens(); i++) {
104             String JavaDoc token = st.nextToken();
105             tokens[i] = token;
106             byte tokenCode = findTokenCode(token);
107             tokenCodes[i] = tokenCode;
108             if(tokenCode == TOK_NUM) {
109                 parsedDoubles[i] = Double.parseDouble(token);
110             }
111         }
112     }
113
114     private byte findTokenCode(String JavaDoc token) throws RrdException {
115         if(isVariable(token)) {
116             return TOK_VAR;
117         }
118         else if(isNumber(token)) {
119             return TOK_NUM;
120         }
121         else if(token.equals("+")) {
122             return TOK_PLUS;
123         }
124         else if(token.equals("-")) {
125             return TOK_MINUS;
126         }
127         else if(token.equals("*")) {
128             return TOK_MULT;
129         }
130         else if(token.equals("/")) {
131             return TOK_DIV;
132         }
133         else if(token.equals("%")) {
134             return TOK_MOD;
135         }
136         else if(token.equals("SIN")) {
137             return TOK_SIN;
138         }
139         else if(token.equals("COS")) {
140             return TOK_COS;
141         }
142         else if(token.equals("LOG")) {
143             return TOK_LOG;
144         }
145         else if(token.equals("EXP")) {
146             return TOK_EXP;
147         }
148         else if(token.equals("FLOOR")) {
149             return TOK_FLOOR;
150         }
151         else if(token.equals("CEIL")) {
152             return TOK_CEIL;
153         }
154         else if(token.equals("ROUND")) {
155             return TOK_ROUND;
156         }
157         else if(token.equals("POW")) {
158             return TOK_POW;
159         }
160         else if(token.equals("ABS")) {
161             return TOK_ABS;
162         }
163         else if(token.equals("SQRT")) {
164             return TOK_SQRT;
165         }
166         else if(token.equals("RANDOM")) {
167             return TOK_RANDOM;
168         }
169         else if(token.equals("LT")) {
170             return TOK_LT;
171         }
172         else if(token.equals("LE")) {
173             return TOK_LE;
174         }
175         else if(token.equals("GT")) {
176             return TOK_GT;
177         }
178         else if(token.equals("GE")) {
179             return TOK_GE;
180         }
181         else if(token.equals("EQ")) {
182             return TOK_EQ;
183         }
184         else if(token.equals("IF")) {
185             return TOK_IF;
186         }
187         else if(token.equals("MIN")) {
188             return TOK_MIN;
189         }
190         else if(token.equals("MAX")) {
191             return TOK_MAX;
192         }
193         else if(token.equals("LIMIT")) {
194             return TOK_LIMIT;
195         }
196         else if(token.equals("DUP")) {
197             return TOK_DUP;
198         }
199         else if(token.equals("EXC")) {
200             return TOK_EXC;
201         }
202         else if(token.equals("POP")) {
203             return TOK_POP;
204         }
205         else if(token.equals("UN")) {
206             return TOK_UN;
207         }
208         else if(token.equals("UNKN")) {
209             return TOK_UNKN;
210         }
211
212         /* not supported yet
213         else if(token.equals("NOW")) {
214             return TOK_NOW;
215         }
216         else if(token.equals("TIME")) {
217             return TOK_TIME;
218         }
219         */

220         else if(token.equals("PI")) {
221             return TOK_PI;
222         }
223         else if(token.equals("E")) {
224             return TOK_E;
225         }
226         else if(token.equals("AND")) {
227             return TOK_AND;
228         }
229         else if(token.equals("OR")) {
230             return TOK_OR;
231         }
232         else if(token.equals("XOR")) {
233             return TOK_XOR;
234         }
235         else {
236             throw new RrdException("Unknown RPN token encountered: " + token);
237         }
238     }
239
240     private static boolean isNumber(String JavaDoc token) {
241         try {
242             Double.parseDouble(token);
243             return true;
244         }
245         catch(NumberFormatException JavaDoc nfe) {
246             return false;
247         }
248     }
249
250     private static boolean isVariable(String JavaDoc token) {
251         return token.equals(VAR_PLACEHOLDER);
252     }
253
254     double calculate() throws RrdException {
255         resetCalculator();
256         for(int i = 0; i < tokenCodes.length; i++) {
257             byte tokenCode = tokenCodes[i];
258             double x1, x2, x3;
259             switch(tokenCode) {
260                 case TOK_NUM:
261                     push(parsedDoubles[i]); break;
262                 case TOK_VAR:
263                     push(value); break;
264                 case TOK_PLUS:
265                     push(pop() + pop()); break;
266                 case TOK_MINUS:
267                     x2 = pop(); x1 = pop(); push(x1 - x2); break;
268                 case TOK_MULT:
269                     push(pop() * pop()); break;
270                 case TOK_DIV:
271                     x2 = pop(); x1 = pop(); push(x1 / x2); break;
272                 case TOK_MOD:
273                     x2 = pop(); x1 = pop(); push(x1 % x2); break;
274                 case TOK_SIN:
275                     push(Math.sin(pop())); break;
276                 case TOK_COS:
277                     push(Math.cos(pop())); break;
278                 case TOK_LOG:
279                     push(Math.log(pop())); break;
280                 case TOK_EXP:
281                     push(Math.exp(pop())); break;
282                 case TOK_FLOOR:
283                     push(Math.floor(pop())); break;
284                 case TOK_CEIL:
285                     push(Math.ceil(pop())); break;
286                 case TOK_ROUND:
287                     push(Math.round(pop())); break;
288                 case TOK_POW:
289                     x2 = pop(); x1 = pop(); push(Math.pow(x1, x2)); break;
290                 case TOK_ABS:
291                     push(Math.abs(pop())); break;
292                 case TOK_SQRT:
293                     push(Math.sqrt(pop())); break;
294                 case TOK_RANDOM:
295                     push(Math.random()); break;
296                 case TOK_LT:
297                     x2 = pop(); x1 = pop(); push(x1 < x2? 1: 0); break;
298                 case TOK_LE:
299                     x2 = pop(); x1 = pop(); push(x1 <= x2? 1: 0); break;
300                 case TOK_GT:
301                     x2 = pop(); x1 = pop(); push(x1 > x2? 1: 0); break;
302                 case TOK_GE:
303                     x2 = pop(); x1 = pop(); push(x1 >= x2? 1: 0); break;
304                 case TOK_EQ:
305                     x2 = pop(); x1 = pop(); push(x1 == x2? 1: 0); break;
306                 case TOK_IF:
307                     x3 = pop(); x2 = pop(); x1 = pop(); push(x1 != 0? x2: x3); break;
308                 case TOK_MIN:
309                     push(Math.min(pop(), pop())); break;
310                 case TOK_MAX:
311                     push(Math.max(pop(), pop())); break;
312                 case TOK_LIMIT:
313                     x3 = pop(); x2 = pop(); x1 = pop();
314                     push(x1 < x2 || x1 > x3? Double.NaN: x1); break;
315                 case TOK_DUP:
316                     x1 = pop(); push(x1); push(x1); break;
317                 case TOK_EXC:
318                     x2 = pop(); x1 = pop(); push(x2); push(x1); break;
319                 case TOK_POP:
320                     pop(); break;
321                 case TOK_UN:
322                     push(Double.isNaN(pop())? 1: 0); break;
323                 case TOK_UNKN:
324                     push(Double.NaN); break;
325                 /* not supported yet
326                 case TOK_NOW:
327                     push(Util.getTime()); break;
328                 case TOK_TIME:
329                     push(timestamp); break;
330                 */

331                 case TOK_PI:
332                     push(Math.PI); break;
333                 case TOK_E:
334                     push(Math.E); break;
335                 case TOK_AND:
336                     x2 = pop(); x1 = pop(); push((x1 != 0 && x2 != 0)? 1: 0); break;
337                 case TOK_OR:
338                     x2 = pop(); x1 = pop(); push((x1 != 0 || x2 != 0)? 1: 0); break;
339                 case TOK_XOR:
340                     x2 = pop(); x1 = pop();
341                     push(((x1 != 0 && x2 == 0) || (x1 == 0 && x2 != 0))? 1: 0); break;
342                 default:
343                     throw new RrdException("Unexpected RPN token encountered [" +
344                         tokenCode + "]");
345             }
346         }
347         double retVal = pop();
348         if(!isStackEmpty()) {
349             throw new RrdException("Stack not empty at the end of calculation. " +
350                 "Probably bad RPN expression");
351         }
352         return retVal;
353     }
354
355     void push(double x) throws RrdException {
356         stack.push(x);
357     }
358
359     double pop() throws RrdException {
360         return stack.pop();
361     }
362
363     void resetCalculator() {
364         stack.reset();
365     }
366
367     boolean isStackEmpty() {
368         return stack.isEmpty();
369     }
370
371     class RpnStack {
372         static final int MAX_STACK_SIZE = 1000;
373         private double[] stack = new double[MAX_STACK_SIZE];
374         private int pos = 0;
375
376         void push(double x) throws RrdException {
377             if(pos >= MAX_STACK_SIZE) {
378                 throw new RrdException(
379                     "PUSH failed, RPN stack full [" + MAX_STACK_SIZE + "]");
380             }
381             stack[pos++] = x;
382         }
383
384         double pop() throws RrdException {
385             if(pos <= 0) {
386                 throw new RrdException("POP failed, RPN stack is empty ");
387             }
388             return stack[--pos];
389         }
390
391         void reset() {
392             pos = 0;
393         }
394
395         boolean isEmpty() {
396             return pos == 0;
397         }
398     }
399
400 /*
401     public static void main(String[] args) throws RrdException {
402         RpnCalculator c = new RpnCalculator("2,3,/,value,+");
403         c.setValue(5);
404         System.out.println(c.calculate());
405     }
406 */

407 }
408
Popular Tags