📄 rpncalculator.java
字号:
/* ============================================================
* JRobin : Pure java implementation of RRDTool's functionality
* ============================================================
*
* Project Info: http://www.jrobin.org
* Project Lead: Sasa Markovic (saxon@jrobin.org);
*
* (C) Copyright 2003, by Sasa Markovic.
*
* Developers: Sasa Markovic (saxon@jrobin.org)
* Arne Vandamme (cobralord@jrobin.org)
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
package net.jumperz.ext.org.jrobin.core;
import java.util.StringTokenizer;
class RpnCalculator {
static final String VAR_PLACEHOLDER = "value";
private static final byte TOK_VAR = 0;
private static final byte TOK_NUM = 1;
private static final byte TOK_PLUS = 2;
private static final byte TOK_MINUS = 3;
private static final byte TOK_MULT = 4;
private static final byte TOK_DIV = 5;
private static final byte TOK_MOD = 6;
private static final byte TOK_SIN = 7;
private static final byte TOK_COS = 8;
private static final byte TOK_LOG = 9;
private static final byte TOK_EXP = 10;
private static final byte TOK_FLOOR = 11;
private static final byte TOK_CEIL = 12;
private static final byte TOK_ROUND = 13;
private static final byte TOK_POW = 14;
private static final byte TOK_ABS = 15;
private static final byte TOK_SQRT = 16;
private static final byte TOK_RANDOM = 17;
private static final byte TOK_LT = 18;
private static final byte TOK_LE = 19;
private static final byte TOK_GT = 20;
private static final byte TOK_GE = 21;
private static final byte TOK_EQ = 22;
private static final byte TOK_IF = 23;
private static final byte TOK_MIN = 24;
private static final byte TOK_MAX = 25;
private static final byte TOK_LIMIT = 26;
private static final byte TOK_DUP = 27;
private static final byte TOK_EXC = 28;
private static final byte TOK_POP = 29;
private static final byte TOK_UN = 30;
private static final byte TOK_UNKN = 31;
// private static final byte TOK_NOW = 32;
// private static final byte TOK_TIME = 33;
private static final byte TOK_PI = 34;
private static final byte TOK_E = 35;
private static final byte TOK_AND = 36;
private static final byte TOK_OR = 37;
private static final byte TOK_XOR = 38;
private String[] tokens;
private byte[] tokenCodes;
private double[] parsedDoubles;
private RpnStack stack = new RpnStack();
private String rpnExpression;
private double value;
// private long timestamp;
RpnCalculator(String rpnExpression) throws RrdException {
this.rpnExpression = rpnExpression;
createTokens();
}
void setValue(double value) {
this.value = value;
}
/* not supported yet
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
*/
private void createTokens() throws RrdException {
StringTokenizer st = new StringTokenizer(rpnExpression, ",");
int count = st.countTokens();
tokens = new String[count];
tokenCodes = new byte[count];
parsedDoubles = new double[count];
for(int i = 0; st.hasMoreTokens(); i++) {
String token = st.nextToken();
tokens[i] = token;
byte tokenCode = findTokenCode(token);
tokenCodes[i] = tokenCode;
if(tokenCode == TOK_NUM) {
parsedDoubles[i] = Double.parseDouble(token);
}
}
}
private byte findTokenCode(String token) throws RrdException {
if(isVariable(token)) {
return TOK_VAR;
}
else if(isNumber(token)) {
return TOK_NUM;
}
else if(token.equals("+")) {
return TOK_PLUS;
}
else if(token.equals("-")) {
return TOK_MINUS;
}
else if(token.equals("*")) {
return TOK_MULT;
}
else if(token.equals("/")) {
return TOK_DIV;
}
else if(token.equals("%")) {
return TOK_MOD;
}
else if(token.equals("SIN")) {
return TOK_SIN;
}
else if(token.equals("COS")) {
return TOK_COS;
}
else if(token.equals("LOG")) {
return TOK_LOG;
}
else if(token.equals("EXP")) {
return TOK_EXP;
}
else if(token.equals("FLOOR")) {
return TOK_FLOOR;
}
else if(token.equals("CEIL")) {
return TOK_CEIL;
}
else if(token.equals("ROUND")) {
return TOK_ROUND;
}
else if(token.equals("POW")) {
return TOK_POW;
}
else if(token.equals("ABS")) {
return TOK_ABS;
}
else if(token.equals("SQRT")) {
return TOK_SQRT;
}
else if(token.equals("RANDOM")) {
return TOK_RANDOM;
}
else if(token.equals("LT")) {
return TOK_LT;
}
else if(token.equals("LE")) {
return TOK_LE;
}
else if(token.equals("GT")) {
return TOK_GT;
}
else if(token.equals("GE")) {
return TOK_GE;
}
else if(token.equals("EQ")) {
return TOK_EQ;
}
else if(token.equals("IF")) {
return TOK_IF;
}
else if(token.equals("MIN")) {
return TOK_MIN;
}
else if(token.equals("MAX")) {
return TOK_MAX;
}
else if(token.equals("LIMIT")) {
return TOK_LIMIT;
}
else if(token.equals("DUP")) {
return TOK_DUP;
}
else if(token.equals("EXC")) {
return TOK_EXC;
}
else if(token.equals("POP")) {
return TOK_POP;
}
else if(token.equals("UN")) {
return TOK_UN;
}
else if(token.equals("UNKN")) {
return TOK_UNKN;
}
/* not supported yet
else if(token.equals("NOW")) {
return TOK_NOW;
}
else if(token.equals("TIME")) {
return TOK_TIME;
}
*/
else if(token.equals("PI")) {
return TOK_PI;
}
else if(token.equals("E")) {
return TOK_E;
}
else if(token.equals("AND")) {
return TOK_AND;
}
else if(token.equals("OR")) {
return TOK_OR;
}
else if(token.equals("XOR")) {
return TOK_XOR;
}
else {
throw new RrdException("Unknown RPN token encountered: " + token);
}
}
private static boolean isNumber(String token) {
try {
Double.parseDouble(token);
return true;
}
catch(NumberFormatException nfe) {
return false;
}
}
private static boolean isVariable(String token) {
return token.equals(VAR_PLACEHOLDER);
}
double calculate() throws RrdException {
resetCalculator();
for(int i = 0; i < tokenCodes.length; i++) {
byte tokenCode = tokenCodes[i];
double x1, x2, x3;
switch(tokenCode) {
case TOK_NUM:
push(parsedDoubles[i]); break;
case TOK_VAR:
push(value); break;
case TOK_PLUS:
push(pop() + pop()); break;
case TOK_MINUS:
x2 = pop(); x1 = pop(); push(x1 - x2); break;
case TOK_MULT:
push(pop() * pop()); break;
case TOK_DIV:
x2 = pop(); x1 = pop(); push(x1 / x2); break;
case TOK_MOD:
x2 = pop(); x1 = pop(); push(x1 % x2); break;
case TOK_SIN:
push(Math.sin(pop())); break;
case TOK_COS:
push(Math.cos(pop())); break;
case TOK_LOG:
push(Math.log(pop())); break;
case TOK_EXP:
push(Math.exp(pop())); break;
case TOK_FLOOR:
push(Math.floor(pop())); break;
case TOK_CEIL:
push(Math.ceil(pop())); break;
case TOK_ROUND:
push(Math.round(pop())); break;
case TOK_POW:
x2 = pop(); x1 = pop(); push(Math.pow(x1, x2)); break;
case TOK_ABS:
push(Math.abs(pop())); break;
case TOK_SQRT:
push(Math.sqrt(pop())); break;
case TOK_RANDOM:
push(Math.random()); break;
case TOK_LT:
x2 = pop(); x1 = pop(); push(x1 < x2? 1: 0); break;
case TOK_LE:
x2 = pop(); x1 = pop(); push(x1 <= x2? 1: 0); break;
case TOK_GT:
x2 = pop(); x1 = pop(); push(x1 > x2? 1: 0); break;
case TOK_GE:
x2 = pop(); x1 = pop(); push(x1 >= x2? 1: 0); break;
case TOK_EQ:
x2 = pop(); x1 = pop(); push(x1 == x2? 1: 0); break;
case TOK_IF:
x3 = pop(); x2 = pop(); x1 = pop(); push(x1 != 0? x2: x3); break;
case TOK_MIN:
push(Math.min(pop(), pop())); break;
case TOK_MAX:
push(Math.max(pop(), pop())); break;
case TOK_LIMIT:
x3 = pop(); x2 = pop(); x1 = pop();
push(x1 < x2 || x1 > x3? Double.NaN: x1); break;
case TOK_DUP:
x1 = pop(); push(x1); push(x1); break;
case TOK_EXC:
x2 = pop(); x1 = pop(); push(x2); push(x1); break;
case TOK_POP:
pop(); break;
case TOK_UN:
push(Double.isNaN(pop())? 1: 0); break;
case TOK_UNKN:
push(Double.NaN); break;
/* not supported yet
case TOK_NOW:
push(Util.getTime()); break;
case TOK_TIME:
push(timestamp); break;
*/
case TOK_PI:
push(Math.PI); break;
case TOK_E:
push(Math.E); break;
case TOK_AND:
x2 = pop(); x1 = pop(); push((x1 != 0 && x2 != 0)? 1: 0); break;
case TOK_OR:
x2 = pop(); x1 = pop(); push((x1 != 0 || x2 != 0)? 1: 0); break;
case TOK_XOR:
x2 = pop(); x1 = pop();
push(((x1 != 0 && x2 == 0) || (x1 == 0 && x2 != 0))? 1: 0); break;
default:
throw new RrdException("Unexpected RPN token encountered [" +
tokenCode + "]");
}
}
double retVal = pop();
if(!isStackEmpty()) {
throw new RrdException("Stack not empty at the end of calculation. " +
"Probably bad RPN expression");
}
return retVal;
}
void push(double x) throws RrdException {
stack.push(x);
}
double pop() throws RrdException {
return stack.pop();
}
void resetCalculator() {
stack.reset();
}
boolean isStackEmpty() {
return stack.isEmpty();
}
class RpnStack {
static final int MAX_STACK_SIZE = 1000;
private double[] stack = new double[MAX_STACK_SIZE];
private int pos = 0;
void push(double x) throws RrdException {
if(pos >= MAX_STACK_SIZE) {
throw new RrdException(
"PUSH failed, RPN stack full [" + MAX_STACK_SIZE + "]");
}
stack[pos++] = x;
}
double pop() throws RrdException {
if(pos <= 0) {
throw new RrdException("POP failed, RPN stack is empty ");
}
return stack[--pos];
}
void reset() {
pos = 0;
}
boolean isEmpty() {
return pos == 0;
}
}
/*
public static void main(String[] args) throws RrdException {
RpnCalculator c = new RpnCalculator("2,3,/,value,+");
c.setValue(5);
System.out.println(c.calculate());
}
*/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -