// 文字列式計算エンジン // 1998 N.Inoue // public class Calc { private final static String FUNCTION[] = {"sin", "cos", "tan", "log"}; private final static int FI_SIN = 0; private final static int FI_COS = 1; private final static int FI_TAN = 2; private final static int FI_LOG = 3; private final static int MAX_FI = 3; /** * 定数の式を計算して答えを返す * @param str 式 */ static public double calc(String str) { return calc(str, 0); } /** * 文字の入った式で、文字の値を代入して計算して答えを返す * @param str 文字の式 * @param v 文字の値 * @param c 文字 */ static public double calc(String str, double v, char c) { StringBuffer strbuf = new StringBuffer(str); int strlen = str.length(); for(int i=0; i= 'a')&&(c <= 'z')) return true; else return false; } /** * xの入った式で、xの値を代入して計算して答えを返す * @param str xの式 * @param x xの値 */ static public double calc(String str, double x) { double answer = 0.0; double number = 0.0; double kou = 1.0; double jkou = 1.0; boolean jou = false; char cchr = '*'; int decimal = 0; int plusminus = 1; int strpos = 0; int kdepth = 0; int startpos = 0; // 空文字列の答えは0を返す if(str.length() == 0) return 0.0; // 関数を数値に変換 String funcstr; String numstr; int sl; for(int i = 0; i <= MAX_FI; i++) { funcstr = FUNCTION[i]; sl = funcstr.length(); while((startpos = str.indexOf(funcstr)) != -1) { strpos = startpos + sl; kdepth = 1; do { strpos++; if(str.charAt(strpos) == '(') kdepth++; else if(str.charAt(strpos) == ')') kdepth--; }while(kdepth > 0); switch(i) { case FI_SIN: number = Math.sin(calc(str.substring(startpos+sl+1, strpos), x)); break; case FI_COS: number = Math.cos(calc(str.substring(startpos+sl+1, strpos), x)); break; case FI_TAN: number = Math.tan(calc(str.substring(startpos+sl+1, strpos), x)); break; case FI_LOG: number = Math.log(calc(str.substring(startpos+sl+1, strpos), x)); break; default: number = 0.0; } numstr = Double.toString(number); if(number<0) numstr = "(" + numstr + ")"; str = str.substring(0, startpos) + numstr + str.substring(strpos+1); } } // 式の読解と計算 strpos = 0; number = 0.0; do { if(Character.isDigit(str.charAt(strpos))) { if(decimal<0) { number = number + Character.digit(str.charAt(strpos), 10)*Math.pow(10, decimal); decimal--; } else number = number*10 + Character.digit(str.charAt(strpos), 10); continue; } else switch(str.charAt(strpos)) { case 'x': number = x; continue; case '(': kdepth = 1; startpos = strpos; do { strpos++; if(str.charAt(strpos) == '(') kdepth++; else if(str.charAt(strpos) == ')') kdepth--; }while(kdepth > 0); number = calc(str.substring(startpos+1, strpos), x); continue; case '|': startpos = strpos; do strpos++; while(str.charAt(strpos) != '|'); number = Math.abs(calc(str.substring(startpos+1, strpos), x)); continue; case '.': decimal = -1; continue; case '+': answer = answer + plusminus*calcsub(kou, cchr, number, jou, jkou); number = 0.0; decimal = 0; plusminus = 1; kou = 1.0; cchr = '*'; jou = false; continue; case '-': answer = answer + plusminus*calcsub(kou, cchr, number, jou, jkou); number = 0.0; decimal = 0; plusminus = -1; kou = 1.0; cchr = '*'; jou = false; continue; case '*': kou = calcsub(kou, cchr, number, jou, jkou); cchr = '*'; jou = false; number = 0.0; decimal = 0; continue; case '/': kou = calcsub(kou, cchr, number, jou, jkou); cchr = '/'; jou = false; number = 0.0; decimal = 0; continue; case '^': if(jou) jkou = Math.pow(jkou, number); else jkou = number; jou = true; number = 0.0; decimal = 0; continue; } }while(str.length() > ++strpos); answer = answer + plusminus*calcsub(kou, cchr, number, jou, jkou); return answer; } final static double calcsub(double num_a, char chr, double num_b, boolean jou, double jkou) { if(!jou) switch(chr) { case '*': return num_a * num_b; case '/': return num_a / num_b; } else switch(chr) { case '*': return num_a * Math.pow(jkou, num_b); case '/': return num_a / Math.pow(jkou, num_b); } return 0; } }