سؤال

ما هي أذكى طريقة لتصميم محلل الرياضيات؟ما أعنيه هو وظيفة تأخذ سلسلة رياضية (مثل:"2 + 3 / 2 + (2 * 5)") وإرجاع القيمة المحسوبة؟لقد كتبت واحدة في VB6 منذ زمن طويل ولكن انتهى الأمر إلى كونها طريقة منتفخة وليست محمولة جدًا (أو ذكية في هذا الشأن ...).نقدر الأفكار العامة أو الكود الزائف أو الكود الحقيقي.

هل كانت مفيدة؟

المحلول

قد يتضمن النهج الجيد خطوتين.الخطوة الأولى تنطوي على تحويل التعبير من infix إلى postfix (على سبيل المثالعبر ساحة النقل في ديكسترا) الرموز.بمجرد الانتهاء من ذلك، سيكون من السهل جدًا كتابة ملف مقيم postfix.

نصائح أخرى

لقد كتبت بعض التدوينات حول تصميم محلل رياضيات.هناك جنرال مقدمة, المعرفة الأساسية حول القواعد, نموذج التنفيذ مكتوب في روبي و أ حزمة اختبار.ربما ستجد هذه المواد مفيدة.

لديك عدة طرق.يمكنك إنشاء تعليمات برمجية ديناميكية وتنفيذها للحصول على الإجابة دون الحاجة إلى كتابة الكثير من التعليمات البرمجية.ما عليك سوى إجراء بحث عن التعليمات البرمجية التي تم إنشاؤها في وقت التشغيل في .NET وهناك الكثير من الأمثلة حولها.

وبدلاً من ذلك، يمكنك إنشاء محلل فعلي وإنشاء شجرة تحليل صغيرة تُستخدم بعد ذلك لتقييم التعبير.مرة أخرى، هذا أمر بسيط جدًا بالنسبة للتعبيرات الأساسية.تحقق من codeplex لأنني أعتقد أن لديهم محللًا رياضيًا هناك.أو ابحث فقط عن BNF الذي سيتضمن أمثلة.أي موقع ويب يقدم مفاهيم المترجم سيتضمن ذلك كمثال أساسي.

مقيم التعبير Codeplex

أعلم أن هذا أمر قديم، ولكنني واجهت هذا أثناء محاولة تطوير آلة حاسبة كجزء من تطبيق أكبر وواجهت بعض المشكلات باستخدام الإجابة المقبولة.كانت الروابط مفيدة للغاية في فهم هذه المشكلة وحلها ولا ينبغي استبعادها.كنت أكتب تطبيق Android بلغة Java ولكل عنصر في التعبير "سلسلة"، قمت بالفعل بتخزين سلسلة في ArrayList أثناء قيام المستخدم بالكتابة على لوحة المفاتيح.بالنسبة للتحويل من infix إلى postfix، قمت بالتكرار عبر كل سلسلة في ArrayList، ثم قمت بتقييم ArrayList of Strings التي تم ترتيبها حديثًا.كان هذا أمرًا رائعًا بالنسبة لعدد صغير من المعاملات/المشغلين، ولكن العمليات الحسابية الأطول كانت متوقفة باستمرار، خاصة عندما بدأت التعبيرات في التقييم إلى أعداد غير صحيحة.في الرابط المقدم ل تحويل Infix إلى Postfix, ، فإنه يقترح ظهور المكدس إذا كان العنصر الممسوح ضوئيًا عامل تشغيل وكان لعنصر topStack أسبقية أعلى.لقد وجدت أن هذا صحيح تقريبًا.أدى ظهور عنصر topStack إذا كانت أسبقيته أعلى أو مساوية للمشغل الذي تم فحصه إلى جعل حساباتي صحيحة في النهاية.نأمل أن يساعد هذا أي شخص يعمل على حل هذه المشكلة، شكرًا لجوستين بولي (وفاس؟) لتوفير بعض الروابط التي لا تقدر بثمن.

إذا كان لديك تطبيق "يعمل دائمًا"، فما عليك سوى نشر سلسلة الرياضيات على Google وتحليل النتيجة.طريقة بسيطة ولكن لست متأكدًا مما إذا كان هذا هو ما تحتاجه - ولكنها ذكية بطريقة ما على ما أعتقد.

السؤال ذو الصلة محلل المعادلة (التعبير) مع الأسبقية؟ لديه بعض المعلومات الجيدة حول كيفية البدء بهذا أيضًا.

-آدم

بافتراض أن إدخالك عبارة عن تعبير infix بتنسيق سلسلة، فيمكنك تحويله إلى postfix وباستخدام زوج من الأكوام:مكدس المشغل ومكدس المعامل، اعمل على الحل من هناك.يمكنك العثور على معلومات الخوارزمية العامة على رابط ويكيبيديا.

ANTLR هو مولد محلل LL(*) لطيف جدًا.أوصي به بشدة.

يرغب المطورون دائمًا في اتباع نهج نظيف، ومحاولة تنفيذ منطق التحليل من الألف إلى الياء، وعادةً ما ينتهي الأمر بـ خوارزمية Dijkstra Shunting-Yard.والنتيجة هي رمز ذو مظهر أنيق، ولكن من المحتمل أن يكون مليئًا بالأخطاء.لقد قمت بتطوير واجهة برمجة التطبيقات هذه، JMEP, ، هذا يفعل كل ذلك، لكن الأمر استغرق مني سنوات للحصول على كود ثابت.

حتى مع كل هذا العمل، يمكنك أن ترى حتى من صفحة المشروع أنني أفكر جديًا في التحول إلى استخدام JavaCC أو ANTLR، حتى بعد كل هذا العمل الذي تم إنجازه بالفعل.

بعد 11 سنة من وقت طرح هذا السؤال:إذا كنت لا ترغب في إعادة اختراع العجلة، فهناك العديد من محللي الرياضيات الغريبين.

هناك واحدة كتبتها منذ سنوات وهي تدعم العمليات الحسابية، وحل المعادلات، وحساب التفاضل والتكامل، والإحصاءات الأساسية، وتعريف الوظيفة/الصيغة، والرسوم البيانية، وما إلى ذلك.

تسمى بارسيرنج وهو مجاني.

تقييم التعبير بسيط مثل:

    MathExpression expr = new MathExpression("(34+32)-44/(8+9(3+2))-22"); 
    System.out.println("result: " + expr.solve());

    result: 43.16981132075472

أو باستخدام المتغيرات وحساب التعبيرات البسيطة:

 MathExpression expr = new MathExpression("r=3;P=2*pi*r;"); 
System.out.println("result: " + expr.getValue("P"));

أو باستخدام الوظائف:

MathExpression expr = new MathExpression("f(x)=39*sin(x^2)+x^3*cos(x);f(3)"); 
System.out.println("result: " + expr.solve());

result: -10.65717648378352

أو لتقييم المشتق عند نقطة معينة (لاحظ أنه يقوم بالتمايز الرمزي (وليس العددي) خلف الكواليس، وبالتالي فإن الدقة لا تقتصر على أخطاء التقديرات الرقمية):

MathExpression expr = new MathExpression("f(x)=x^3*ln(x); diff(f,3,1)"); 
System.out.println("result: " + expr.solve());

 result: 38.66253179403897

الذي يفرق x^3 * ln(x) مرة واحدة عند x=3.عدد المرات التي يمكنك التمييز فيها هو 1 في الوقت الحالي.

أو للتكامل العددي:

MathExpression expr = new MathExpression("f(x)=2*x; intg(f,1,3)"); 
System.out.println("result: " + expr.solve());

result: 7.999999999998261... approx: 8

هذا المحلل سريع بشكل لائق ولديه الكثير من الوظائف الأخرى.

تم الانتهاء من العمل على نقله إلى Swift عبر الارتباطات بـ Objective C واستخدمناه في تطبيقات الرسوم البيانية من بين حالات الاستخدام التكرارية الأخرى.

تنصل:ParserNG من تأليفي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top