আমি এই জাতীয় String
মানগুলি থেকে সাধারণ গণিতের প্রকাশগুলি মূল্যায়নের জন্য একটি জাভা রুটিন লেখার চেষ্টা করছি :
"5+3"
"10-40"
"10*3"
আমি-তবে-অন্য বিবৃতিগুলি অনেক এড়াতে চাই। কিভাবে আমি এটি করতে পারব?
আমি এই জাতীয় String
মানগুলি থেকে সাধারণ গণিতের প্রকাশগুলি মূল্যায়নের জন্য একটি জাভা রুটিন লেখার চেষ্টা করছি :
"5+3"
"10-40"
"10*3"
আমি-তবে-অন্য বিবৃতিগুলি অনেক এড়াতে চাই। কিভাবে আমি এটি করতে পারব?
উত্তর:
JDK1.6 এর সাহায্যে আপনি অন্তর্নির্মিত জাভাস্ক্রিপ্ট ইঞ্জিনটি ব্যবহার করতে পারেন।
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
public class Test {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = "40+2";
System.out.println(engine.eval(foo));
}
}
return (Double) engine.eval(foo);
new javax.script.ScriptEngineManager().getEngineByName("JavaScript") .eval("var f = new java.io.FileWriter('hello.txt'); f.write('UNLIMITED POWER!'); f.close();");
- জাভাস্ক্রিপ্টের মাধ্যমে একটি ফাইল লিখবে (ডিফল্টরূপে) প্রোগ্রামটির বর্তমান ডিরেক্টরি
eval
এই প্রশ্নের উত্তর দেওয়ার জন্য আমি পাটিগণিতের প্রকাশের জন্য এই পদ্ধতিটি লিখেছি । এটি সংযোজন, বিয়োগ, গুণ, বিভাজন, ক্ষয়ক্ষেত্র ( ^
প্রতীক ব্যবহার করে ) এবং কয়েকটি প্রাথমিক ফাংশন করে sqrt
। এটি ব্যবহার গোষ্ঠীবদ্ধ সমর্থন (
... )
, এবং এটি অপারেটর পায় প্রাধান্য এবং associativity সঠিক নিয়ম।
public static double eval(final String str) {
return new Object() {
int pos = -1, ch;
void nextChar() {
ch = (++pos < str.length()) ? str.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') nextChar();
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
return x;
}
// Grammar:
// expression = term | expression `+` term | expression `-` term
// term = factor | term `*` factor | term `/` factor
// factor = `+` factor | `-` factor | `(` expression `)`
// | number | functionName factor | factor `^` factor
double parseExpression() {
double x = parseTerm();
for (;;) {
if (eat('+')) x += parseTerm(); // addition
else if (eat('-')) x -= parseTerm(); // subtraction
else return x;
}
}
double parseTerm() {
double x = parseFactor();
for (;;) {
if (eat('*')) x *= parseFactor(); // multiplication
else if (eat('/')) x /= parseFactor(); // division
else return x;
}
}
double parseFactor() {
if (eat('+')) return parseFactor(); // unary plus
if (eat('-')) return -parseFactor(); // unary minus
double x;
int startPos = this.pos;
if (eat('(')) { // parentheses
x = parseExpression();
eat(')');
} else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
x = Double.parseDouble(str.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') { // functions
while (ch >= 'a' && ch <= 'z') nextChar();
String func = str.substring(startPos, this.pos);
x = parseFactor();
if (func.equals("sqrt")) x = Math.sqrt(x);
else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
else throw new RuntimeException("Unknown function: " + func);
} else {
throw new RuntimeException("Unexpected: " + (char)ch);
}
if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation
return x;
}
}.parse();
}
উদাহরণ:
System.out.println(eval("((4 - 2^3 + 1) * -sqrt(3*3+4*4)) / 2"));
আউটপুট: 7.5 (যা সঠিক)
পার্সার একটি পুনরাবৃত্তীয় বংশদ্ভুত পার্সার , সুতরাং অভ্যন্তরীণভাবে এর ব্যাকরণে প্রতিটি স্তরের অপারেটরের অগ্রাধিকারের জন্য পৃথক বিশ্লেষণ পদ্ধতি ব্যবহার করে। আমি এটিকে সংক্ষিপ্ত করে রেখেছি যাতে এটি পরিবর্তন করা সহজ তবে আপনি এখানে কিছু ধারণা দিতে পারেন যার সাথে এটি প্রসারিত করতে পারেন:
ভেরিয়েবল:
ফাংশনগুলির জন্য নামগুলি পড়ার পার্সারের বিটটি কাস্টম ভেরিয়েবলগুলি পরিচালনা করতে খুব সহজেই পরিবর্তিত হতে পারে, eval
পদ্ধতিতে পাস হওয়া ভেরিয়েবল সারণিতে নাম সন্ধান করে Map<String,Double> variables
।
সংকলন এবং মূল্যায়ন পৃথক করুন:
যদি, ভেরিয়েবলগুলির জন্য সমর্থন যোগ করে, আপনি প্রতিবার পার্স না করে পরিবর্তিত ভেরিয়েবলের সাথে একই অভিব্যক্তি কয়েক মিলিয়ন বার মূল্যায়ন করতে চেয়েছিলেন? এটা সম্ভব. পূর্ববর্তী কম্পাইল এক্সপ্রেশন মূল্যায়নের জন্য প্রথমে একটি ইন্টারফেস সংজ্ঞায়িত করুন:
@FunctionalInterface
interface Expression {
double eval();
}
এখন ফিরে আসা সমস্ত পদ্ধতিগুলি পরিবর্তন করুন double
, সুতরাং পরিবর্তে তারা সেই ইন্টারফেসের একটি উদাহরণ ফিরে আসে। জাভা 8 এর ল্যাম্বদা সিনট্যাক্স এটির জন্য দুর্দান্ত কাজ করে। পরিবর্তিত পদ্ধতির একটি উদাহরণ:
Expression parseExpression() {
Expression x = parseTerm();
for (;;) {
if (eat('+')) { // addition
Expression a = x, b = parseTerm();
x = (() -> a.eval() + b.eval());
} else if (eat('-')) { // subtraction
Expression a = x, b = parseTerm();
x = (() -> a.eval() - b.eval());
} else {
return x;
}
}
}
Expression
এটি সংকলিত অভিব্যক্তি (একটি বিমূর্ত সিনট্যাক্স ট্রি ) উপস্থাপন করে এমন একটি পুনরাবৃত্ত গাছ তৈরি করে । তারপরে আপনি এটি একবার সংকলন করতে এবং বিভিন্ন মান সহ বারবার মূল্যায়ন করতে পারেন:
public static void main(String[] args) {
Map<String,Double> variables = new HashMap<>();
Expression exp = parse("x^2 - x + 2", variables);
for (double x = -20; x <= +20; x++) {
variables.put("x", x);
System.out.println(x + " => " + exp.eval());
}
}
বিভিন্ন ডেটাটাইপ:
পরিবর্তে double
, আপনি মূল্যবানকে আরও শক্তিশালী কিছু ব্যবহার করতে BigDecimal
বা এমন একটি শ্রেণি যা জটিল সংখ্যা, বা যুক্তিযুক্ত সংখ্যা (ভগ্নাংশ) প্রয়োগ করে change এমনকি আপনি Object
বাস্তব প্রোগ্রামিং ভাষার মতোই অভিব্যক্তিগুলিতে ডেটাটাইপগুলির কিছু মিশ্রণ ব্যবহার করে এমনকি ব্যবহার করতে পারেন । :)
এই উত্তরের সমস্ত কোড পাবলিক ডোমেনে প্রকাশিত হয়েছে । আনন্দ কর!
double x = parseTerm();
বাম অপারেটরকে মূল্যায়ন করে, এর পরে for (;;) {...}
প্রকৃত অর্ডার স্তরের সফল সংযোজনগুলি (সংযোজন, বিয়োগফল) মূল্যায়ন করে। একই যুক্তিটি হল এবং পার্সেটার্ম পদ্ধতিতে। পার্সফ্যাক্টরের পরবর্তী স্তর নেই, সুতরাং কেবল পদ্ধতি / পরিবর্তনশীল বা প্যারান্থেসিসের ক্ষেত্রে মূল্যায়ন রয়েছে - উপ-এক্সপ্রেশনটি মূল্যায়ন করুন। boolean eat(int charToEat)
CharToEat অক্ষর দিয়ে বর্তমান কার্সার চরিত্রের পদ্ধতি চেক সমতা, যদি পরবর্তী অক্ষরে সমান প্রত্যাবর্তন সত্য এবং পদক্ষেপ কার্সার, আমি নাম ব্যবহার তার জন্য 'স্বীকার করি'।
এটি সমাধানের সঠিক উপায় একটি লেক্সার এবং পার্সার সহ । আপনি এগুলির সাধারণ সংস্করণগুলি নিজেরাই লিখতে পারেন, বা সেই পৃষ্ঠাগুলির জাভা লেক্সার এবং পার্সারগুলির লিঙ্ক রয়েছে।
একটি পুনরাবৃত্ত বংশদ্ভুত পার্সার তৈরি করা সত্যিই একটি ভাল শেখার অনুশীলন।
আমার বিশ্ববিদ্যালয় প্রকল্পের জন্য, আমি উভয় মৌলিক সূত্র এবং আরও জটিল সমীকরণ (বিশেষত পুনরাবৃত্তি অপারেটর) সমর্থনকারী পার্সার / মূল্যায়নকারী খুঁজছিলাম। আমি জাভা এবং .NET কে এমএক্সপার্সার নামে খুব ভাল ওপেন সোর্স লাইব্রেরি পেয়েছি। সিনট্যাক্স সম্পর্কে কিছুটা অনুভূতি বোধ করার জন্য আমি কয়েকটি উদাহরণ দেব, আরও নির্দেশাবলীর জন্য দয়া করে প্রকল্পের ওয়েবসাইটটি দেখুন (বিশেষত টিউটোরিয়াল বিভাগ)।
https://mathparser.org/mxparser-tutorial/
এবং কয়েকটি উদাহরণ
1 - সরল ফারমুলা
Expression e = new Expression("( 2 + 3/4 + sin(pi) )/2");
double v = e.calculate()
2 - ব্যবহারকারী সংজ্ঞায়িত যুক্তি এবং ধ্রুবক
Argument x = new Argument("x = 10");
Constant a = new Constant("a = pi^2");
Expression e = new Expression("cos(a*x)", x, a);
double v = e.calculate()
3 - ব্যবহারকারী সংজ্ঞায়িত ফাংশন
Function f = new Function("f(x, y, z) = sin(x) + cos(y*z)");
Expression e = new Expression("f(3,2,5)", f);
double v = e.calculate()
4 - Iteration
Expression e = new Expression("sum( i, 1, 100, sin(i) )");
double v = e.calculate()
সম্প্রতি পাওয়া গেছে - যদি আপনি সিনট্যাক্সটি চেষ্টা করতে চান (এবং উন্নত ব্যবহারের ক্ষেত্রে দেখুন) আপনি এমএক্সপারসার দ্বারা চালিত স্কেলার ক্যালকুলেটর অ্যাপ্লিকেশনটি ডাউনলোড করতে পারেন ।
শুভেচ্ছান্তে
এভেলেক্স নামে গিটহাবের আরও একটি ওপেন সোর্স লাইব্রেরি এখানে ।
জাভাস্ক্রিপ্ট ইঞ্জিনের বিপরীতে এই পাঠাগারটি শুধুমাত্র গাণিতিক এক্সপ্রেশন মূল্যায়নে মনোনিবেশিত। তদতিরিক্ত, গ্রন্থাগারটি এক্সটেনসিবল এবং বুলিয়ান অপারেটরগুলির পাশাপাশি বন্ধনীগুলির সমর্থন করে।
আপনি বিনশেল দোভাষী চেষ্টা করতে পারেন :
Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));
যদি আপনার জাভা অ্যাপ্লিকেশনটি ইতিমধ্যে অন্য কোনও জেআর ব্যবহার না করে কোনও ডাটাবেস অ্যাক্সেস করে তবে আপনি সহজেই অভিব্যক্তিগুলির মূল্যায়ন করতে পারেন।
কিছু ডাটাবেসের জন্য আপনাকে একটি ডামি টেবিল ব্যবহার করা প্রয়োজন (যেমন, ওরাকলের "দ্বৈত" টেবিল) এবং অন্যরা আপনাকে কোনও সারণী থেকে "নির্বাচন না করে" এক্সপ্রেশন মূল্যায়নের অনুমতি দেবে।
উদাহরণস্বরূপ, SQL সার্ভার বা স্ক্লাইটে
select (((12.10 +12.0))/ 233.0) amount
এবং ওরাকলে
select (((12.10 +12.0))/ 233.0) amount from dual;
ডিবি ব্যবহারের সুবিধা হ'ল আপনি একই সাথে অনেকগুলি এক্সপ্রেশন মূল্যায়ন করতে পারেন। এছাড়াও বেশিরভাগ ডিবি আপনাকে অত্যন্ত জটিল এক্সপ্রেশন ব্যবহার করতে দেয় এবং এতে অনেকগুলি অতিরিক্ত ক্রিয়াকলাপও থাকে যা প্রয়োজনীয় হিসাবে ডাকা যেতে পারে।
তবে একক একাধিক অভিব্যক্তি স্বতন্ত্রভাবে মূল্যায়নের প্রয়োজন হলে কার্যকারিতা ক্ষতিগ্রস্থ হতে পারে, বিশেষত যখন ডিবি একটি নেটওয়ার্ক সার্ভারে থাকে।
মেমরি ডেটাবেস স্ক্লাইট ব্যবহার করে নিম্নলিখিতটি কিছুটা পারফরম্যান্স সমস্যার সমাধান করে।
জাভাতে এখানে একটি সম্পূর্ণ কাজের উদাহরণ
Class. forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount");
rs.next();
System.out.println(rs.getBigDecimal(1));
stat.close();
conn.close();
অবশ্যই আপনি একই সময়ে একাধিক গণনা পরিচালনা করতে উপরের কোডটি প্রসারিত করতে পারেন।
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount, (1+100)/20.0 amount2");
এই নিবন্ধটি বিভিন্ন পন্থা আলোচনা করে। নিবন্ধে উল্লিখিত 2 টি মূল পন্থা এখানে দেওয়া হল:
স্ক্রিপ্টগুলির জন্য জাভা অবজেক্টের রেফারেন্স অন্তর্ভুক্ত করার অনুমতি দেয়।
// Create or retrieve a JexlEngine
JexlEngine jexl = new JexlEngine();
// Create an expression object
String jexlExp = "foo.innerFoo.bar()";
Expression e = jexl.createExpression( jexlExp );
// Create a context and add data
JexlContext jctx = new MapContext();
jctx.set("foo", new Foo() );
// Now evaluate the expression, getting the result
Object o = e.evaluate(jctx);
private static void jsEvalWithVariable()
{
List<String> namesList = new ArrayList<String>();
namesList.add("Jill");
namesList.add("Bob");
namesList.add("Laureen");
namesList.add("Ed");
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
jsEngine.put("namesListKey", namesList);
System.out.println("Executing in script environment...");
try
{
jsEngine.eval("var x;" +
"var names = namesListKey.toArray();" +
"for(x in names) {" +
" println(names[x]);" +
"}" +
"namesListKey.add(\"Dana\");");
}
catch (ScriptException ex)
{
ex.printStackTrace();
}
}
আরেকটি উপায় হ'ল স্প্রিং এক্সপ্রেশন ল্যাঙ্গুয়েজ বা স্পেল ব্যবহার করা যা গাণিতিক অভিব্যক্তিগুলির মূল্যায়নের পাশাপাশি আরও কিছু ঘটে তাই সম্ভবত কিছুটা ওভারকিল। এই এক্সপ্রেশন লাইব্রেরিটি একা একা থাকায় আপনাকে বসন্তের ফ্রেমওয়ার্ক ব্যবহার করতে হবে না। স্পেলের ডকুমেন্টেশন থেকে উদাহরণগুলি অনুলিপি করা হচ্ছে:
ExpressionParser parser = new SpelExpressionParser();
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); //24.0
এখানে আরও সংক্ষিপ্ত স্পেল উদাহরণ এবং সম্পূর্ণ ডক্স এখানে পড়ুন
আমরা যদি এটি প্রয়োগ করতে যাই তবে আমরা নীচের অ্যালগরিদমটি ব্যবহার করতে পারি: -
এখনও পড়ার মতো টোকেন রয়েছে,
1.1 পরবর্তী টোকেন পান। 1.2 যদি টোকেন হয়:
1.2.1 একটি সংখ্যা: মান স্ট্যাকের উপর এটি চাপুন push
১.২.২ একটি ভেরিয়েবল: এর মানটি পান এবং মান স্ট্যাকের উপরে চাপ দিন।
1.2.3 একটি বাম বন্ধনী: এটি অপারেটর স্ট্যাকের উপর চাপ দিন।
1.2.4 একটি ডান প্রথম বন্ধনী:
1 While the thing on top of the operator stack is not a
left parenthesis,
1 Pop the operator from the operator stack.
2 Pop the value stack twice, getting two operands.
3 Apply the operator to the operands, in the correct order.
4 Push the result onto the value stack.
2 Pop the left parenthesis from the operator stack, and discard it.
1.2.5 একটি অপারেটর (এটি কল করুন):
1 While the operator stack is not empty, and the top thing on the
operator stack has the same or greater precedence as thisOp,
1 Pop the operator from the operator stack.
2 Pop the value stack twice, getting two operands.
3 Apply the operator to the operands, in the correct order.
4 Push the result onto the value stack.
2 Push thisOp onto the operator stack.
অপারেটর স্ট্যাকটি খালি না থাকাকালীন অপারেটর স্ট্যাক থেকে অপারেটরটিকে পপ করুন। 2 দুটি অপারেশন পেয়ে দুবার মান স্ট্যাকটি পপ করুন। 3 অপারেটারগুলিকে সঠিক ক্রমে প্রয়োগ করুন। 4 ফলাফলটি মান স্ট্যাকের উপরে ঠেলাও।
এই মুহুর্তে অপারেটর স্ট্যাকটি খালি থাকতে হবে এবং মান স্ট্যাকের মধ্যে একটি মাত্র মান থাকা উচিত যা চূড়ান্ত ফলাফল।
এটি অন্য একটি আকর্ষণীয় বিকল্প https://github.com/Shy-Ta/expression-evaluator-demo
ব্যবহার খুব সহজ এবং কাজটি সম্পন্ন করে, উদাহরণস্বরূপ:
ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");
assertEquals(BigDecimal.valueOf(11), evalExpr.eval());
আমি মনে করি আপনি কোন উপায়ে এটি করেন এটি প্রচুর শর্তযুক্ত বিবৃতি জড়িত হতে চলেছে। তবে আপনার উদাহরণগুলির মতো একক ক্রিয়াকলাপের জন্য আপনি এটিকে 4 এর মধ্যে সীমাবদ্ধ করতে পারেন যদি কোনও কিছুর সাথে বিবৃতি
String math = "1+4";
if (math.split("+").length == 2) {
//do calculation
} else if (math.split("-").length == 2) {
//do calculation
} ...
আপনি যখন "4 + 5 * 6" এর মতো একাধিক ক্রিয়াকলাপ মোকাবেলা করতে চান তখন এটি আরও অনেক জটিল হয়ে যায়।
আপনি যদি কোনও ক্যালকুলেটর তৈরির চেষ্টা করছেন তবে আমি গণনার প্রতিটি বিভাগ একক স্ট্রিংয়ের পরিবর্তে পৃথকভাবে (প্রতিটি সংখ্যা বা অপারেটর) পাস করবো।
জবাব দিতে দেরি হয়ে গেছে তবে জাভাতে অভিব্যক্তি মূল্যায়ন করতে আমি একই পরিস্থিতি পেরিয়ে এসেছি, এটি কারও সাহায্য করতে পারে
MVEL
এক্সপ্রেশনগুলির রানটাইম মূল্যায়ন করে না, String
এটিতে এটি মূল্যায়ন করার জন্য আমরা একটি জাভা কোড লিখতে পারি ।
String expressionStr = "x+y";
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("x", 10);
vars.put("y", 20);
ExecutableStatement statement = (ExecutableStatement) MVEL.compileExpression(expressionStr);
Object result = MVEL.executeExpression(statement, vars);
আপনার সিম্জা ফ্রেমওয়ার্কটি দেখে নিতে পারেন :
ExprEvaluator util = new ExprEvaluator();
IExpr result = util.evaluate("10-40");
System.out.println(result.toString()); // -> "-30"
লক্ষ করুন যে আরও জটিল জটিল এক্সপ্রেশন মূল্যায়ন করা যেতে পারে:
// D(...) gives the derivative of the function Sin(x)*Cos(x)
IAST function = D(Times(Sin(x), Cos(x)), x);
IExpr result = util.evaluate(function);
// print: Cos(x)^2-Sin(x)^2
কোড ইঞ্জেকশন হ্যান্ডলিং সহ JDK1.6 এর জাভাস্ক্রিপ্ট ইঞ্জিন ব্যবহার করে নিম্নলিখিত নমুনা কোডটি ব্যবহার করে দেখুন।
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class EvalUtil {
private static ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
public static void main(String[] args) {
try {
System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || 5 >3 "));
System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || true"));
} catch (Exception e) {
e.printStackTrace();
}
}
public Object eval(String input) throws Exception{
try {
if(input.matches(".*[a-zA-Z;~`#$_{}\\[\\]:\\\\;\"',\\.\\?]+.*")) {
throw new Exception("Invalid expression : " + input );
}
return engine.eval(input);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
এটি আসলে @ বোনের দেওয়া উত্তরটির পরিপূরক। এটিতে একটি সামান্য বাগ রয়েছে যা "-2 ^ 2" -4.0 এর ভুল ফলাফল দেয়। তার জন্য সমস্যাটি সেই বিন্দুতে যেখানে তার মধ্যে ক্ষতিকারক মূল্যায়ন করা হয়। পার্সটার্ম () এর ব্লকে ক্ষুদ্রাকর্ষণটি সরান, এবং আপনি ভাল থাকবেন। নীচে দেখুন, যা @ বোয়ানের উত্তরটি সামান্য পরিবর্তিত হয়েছে। পরিবর্তন মন্তব্যে আছে।
public static double eval(final String str) {
return new Object() {
int pos = -1, ch;
void nextChar() {
ch = (++pos < str.length()) ? str.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') nextChar();
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
return x;
}
// Grammar:
// expression = term | expression `+` term | expression `-` term
// term = factor | term `*` factor | term `/` factor
// factor = `+` factor | `-` factor | `(` expression `)`
// | number | functionName factor | factor `^` factor
double parseExpression() {
double x = parseTerm();
for (;;) {
if (eat('+')) x += parseTerm(); // addition
else if (eat('-')) x -= parseTerm(); // subtraction
else return x;
}
}
double parseTerm() {
double x = parseFactor();
for (;;) {
if (eat('*')) x *= parseFactor(); // multiplication
else if (eat('/')) x /= parseFactor(); // division
else if (eat('^')) x = Math.pow(x, parseFactor()); //exponentiation -> Moved in to here. So the problem is fixed
else return x;
}
}
double parseFactor() {
if (eat('+')) return parseFactor(); // unary plus
if (eat('-')) return -parseFactor(); // unary minus
double x;
int startPos = this.pos;
if (eat('(')) { // parentheses
x = parseExpression();
eat(')');
} else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
x = Double.parseDouble(str.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') { // functions
while (ch >= 'a' && ch <= 'z') nextChar();
String func = str.substring(startPos, this.pos);
x = parseFactor();
if (func.equals("sqrt")) x = Math.sqrt(x);
else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
else throw new RuntimeException("Unknown function: " + func);
} else {
throw new RuntimeException("Unexpected: " + (char)ch);
}
//if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation -> This is causing a bit of problem
return x;
}
}.parse();
}
-2^2 = -4
আসলে একটি স্বাভাবিক, এবং একটি বাগ না। এটি গ্রুপবদ্ধ হয়ে যায় -(2^2)
। উদাহরণস্বরূপ, এটি ডেসমোসে চেষ্টা করুন। আপনার কোডটি আসলে বেশ কয়েকটি বাগ প্রবর্তন করে। প্রথমটি হ'ল ^
আর ডান থেকে বামে দলবদ্ধ করে না। অন্য কথায়, 2^3^2
গ্রুপ পছন্দ করার কথা মনে করা হয় 2^(3^2)
কারণ ^
এটি ডান-অ্যাসোসিয়েটিভ, তবে আপনার পরিবর্তনগুলি এটিকে দলটিকে পছন্দ করে (2^3)^2
। দ্বিতীয়টি হ'ল এবং এর ^
চেয়ে উচ্চতর অগ্রাধিকার রয়েছে বলে মনে করা হয় , তবে আপনার পরিবর্তনগুলি এটির সাথে একই আচরণ করে। আইডিয়োন.আইএনএন 2 এমএমএ দেখুন । *
/
package ExpressionCalculator.expressioncalculator;
import java.text.DecimalFormat;
import java.util.Scanner;
public class ExpressionCalculator {
private static String addSpaces(String exp){
//Add space padding to operands.
//https://regex101.com/r/sJ9gM7/73
exp = exp.replaceAll("(?<=[0-9()])[\\/]", " / ");
exp = exp.replaceAll("(?<=[0-9()])[\\^]", " ^ ");
exp = exp.replaceAll("(?<=[0-9()])[\\*]", " * ");
exp = exp.replaceAll("(?<=[0-9()])[+]", " + ");
exp = exp.replaceAll("(?<=[0-9()])[-]", " - ");
//Keep replacing double spaces with single spaces until your string is properly formatted
/*while(exp.indexOf(" ") != -1){
exp = exp.replace(" ", " ");
}*/
exp = exp.replaceAll(" {2,}", " ");
return exp;
}
public static Double evaluate(String expr){
DecimalFormat df = new DecimalFormat("#.####");
//Format the expression properly before performing operations
String expression = addSpaces(expr);
try {
//We will evaluate using rule BDMAS, i.e. brackets, division, power, multiplication, addition and
//subtraction will be processed in following order
int indexClose = expression.indexOf(")");
int indexOpen = -1;
if (indexClose != -1) {
String substring = expression.substring(0, indexClose);
indexOpen = substring.lastIndexOf("(");
substring = substring.substring(indexOpen + 1).trim();
if(indexOpen != -1 && indexClose != -1) {
Double result = evaluate(substring);
expression = expression.substring(0, indexOpen).trim() + " " + result + " " + expression.substring(indexClose + 1).trim();
return evaluate(expression.trim());
}
}
String operation = "";
if(expression.indexOf(" / ") != -1){
operation = "/";
}else if(expression.indexOf(" ^ ") != -1){
operation = "^";
} else if(expression.indexOf(" * ") != -1){
operation = "*";
} else if(expression.indexOf(" + ") != -1){
operation = "+";
} else if(expression.indexOf(" - ") != -1){ //Avoid negative numbers
operation = "-";
} else{
return Double.parseDouble(expression);
}
int index = expression.indexOf(operation);
if(index != -1){
indexOpen = expression.lastIndexOf(" ", index - 2);
indexOpen = (indexOpen == -1)?0:indexOpen;
indexClose = expression.indexOf(" ", index + 2);
indexClose = (indexClose == -1)?expression.length():indexClose;
if(indexOpen != -1 && indexClose != -1) {
Double lhs = Double.parseDouble(expression.substring(indexOpen, index));
Double rhs = Double.parseDouble(expression.substring(index + 2, indexClose));
Double result = null;
switch (operation){
case "/":
//Prevent divide by 0 exception.
if(rhs == 0){
return null;
}
result = lhs / rhs;
break;
case "^":
result = Math.pow(lhs, rhs);
break;
case "*":
result = lhs * rhs;
break;
case "-":
result = lhs - rhs;
break;
case "+":
result = lhs + rhs;
break;
default:
break;
}
if(indexClose == expression.length()){
expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose);
}else{
expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose + 1);
}
return Double.valueOf(df.format(evaluate(expression.trim())));
}
}
}catch(Exception exp){
exp.printStackTrace();
}
return 0.0;
}
public static void main(String args[]){
Scanner scanner = new Scanner(System.in);
System.out.print("Enter an Mathematical Expression to Evaluate: ");
String input = scanner.nextLine();
System.out.println(evaluate(input));
}
}
কিভাবে ভালো কিছু সম্পর্কে:
String st = "10+3";
int result;
for(int i=0;i<st.length();i++)
{
if(st.charAt(i)=='+')
{
result=Integer.parseInt(st.substring(0, i))+Integer.parseInt(st.substring(i+1, st.length()));
System.out.print(result);
}
}
এবং সেই সাথে প্রতিটি অন্যান্য গাণিতিক অপারেটরের জন্য একই কাজ করুন ..
জিক্স্র্টর শান্টিং-ইয়ার্ড অ্যালগরিদম ব্যবহার করে ইনফিক্স সংকেতটিতে যে কোনও এক্সপ্রেশন স্ট্রিং পোস্টফিক্স স্বরলিপিতে রূপান্তর করা সম্ভব । অ্যালগরিদমের ফলাফল তার পরে পোস্টফিক্স অ্যালগরিদমের ইনপুট হিসাবে পরিবেশন করতে পারে সাথে প্রকাশের ফলাফল দেয়।
আমি জাভা প্রয়োগের সাথে এখানে এটি সম্পর্কে একটি নিবন্ধ লিখেছিলাম
তবুও অন্য বিকল্প: https://github.com/stefanhaustein/expressionparser
আমি উভয়কেই অনুমতি দেওয়ার জন্য একটি সহজ তবে নমনীয় বিকল্প রাখতে এটি প্রয়োগ করেছি:
উপরে লিখিত TreeBuilder একটি অংশ সিএএস ডেমো প্যাকেজের যা প্রতীকী ডেরাইভেশন করে। এখানে একটা হল বেসিক ইন্টারপ্রেটার উদাহরণ এবং আমি একটি নির্মাণ করতে শুরু করেছে অনুবাদক টাইপ করা বিষয় এটি ব্যবহার।
একটি জাভা ক্লাস যা গাণিতিক এক্সপ্রেশন মূল্যায়ন করতে পারে:
package test;
public class Calculator {
public static Double calculate(String expression){
if (expression == null || expression.length() == 0) {
return null;
}
return calc(expression.replace(" ", ""));
}
public static Double calc(String expression) {
if (expression.startsWith("(") && expression.endsWith(")")) {
return calc(expression.substring(1, expression.length() - 1));
}
String[] containerArr = new String[]{expression};
double leftVal = getNextOperand(containerArr);
expression = containerArr[0];
if (expression.length() == 0) {
return leftVal;
}
char operator = expression.charAt(0);
expression = expression.substring(1);
while (operator == '*' || operator == '/') {
containerArr[0] = expression;
double rightVal = getNextOperand(containerArr);
expression = containerArr[0];
if (operator == '*') {
leftVal = leftVal * rightVal;
} else {
leftVal = leftVal / rightVal;
}
if (expression.length() > 0) {
operator = expression.charAt(0);
expression = expression.substring(1);
} else {
return leftVal;
}
}
if (operator == '+') {
return leftVal + calc(expression);
} else {
return leftVal - calc(expression);
}
}
private static double getNextOperand(String[] exp){
double res;
if (exp[0].startsWith("(")) {
int open = 1;
int i = 1;
while (open != 0) {
if (exp[0].charAt(i) == '(') {
open++;
} else if (exp[0].charAt(i) == ')') {
open--;
}
i++;
}
res = calc(exp[0].substring(1, i - 1));
exp[0] = exp[0].substring(i);
} else {
int i = 1;
if (exp[0].charAt(0) == '-') {
i++;
}
while (exp[0].length() > i && isNumber((int) exp[0].charAt(i))) {
i++;
}
res = Double.parseDouble(exp[0].substring(0, i));
exp[0] = exp[0].substring(i);
}
return res;
}
private static boolean isNumber(int c) {
int zero = (int) '0';
int nine = (int) '9';
return (c >= zero && c <= nine) || c =='.';
}
public static void main(String[] args) {
System.out.println(calculate("(((( -6 )))) * 9 * -1"));
System.out.println(calc("(-5.2+-5*-5*((5/4+2)))"));
}
}
জাভাস্ক্রিপ্ট চালানোর জন্য RHINO বা NASHORN এর মতো বাহ্যিক লাইব্রেরি ব্যবহার করা যেতে পারে। এবং জাভাস্ক্রিপ্ট স্ট্রিংটি পার্সিং না করে সহজ সূত্রটি মূল্যায়ন করতে পারে। কোডটি ভালভাবে লেখা থাকলে কোনও পারফরম্যান্স প্রভাব নেই। নীচে RHINO এর সাথে একটি উদাহরণ দেওয়া হল -
public class RhinoApp {
private String simpleAdd = "(12+13+2-2)*2+(12+13+2-2)*2";
public void runJavaScript() {
Context jsCx = Context.enter();
Context.getCurrentContext().setOptimizationLevel(-1);
ScriptableObject scope = jsCx.initStandardObjects();
Object result = jsCx.evaluateString(scope, simpleAdd , "formula", 0, null);
Context.exit();
System.out.println(result);
}
import java.util.*;
public class check {
int ans;
String str="7 + 5";
StringTokenizer st=new StringTokenizer(str);
int v1=Integer.parseInt(st.nextToken());
String op=st.nextToken();
int v2=Integer.parseInt(st.nextToken());
if(op.equals("+")) { ans= v1 + v2; }
if(op.equals("-")) { ans= v1 - v2; }
//.........
}