c#根據公式進行自動計算的實現

 

之前搞了3個不同的方法來實現公式的自動計算,今天又去了老外的codeProject論壇轉了一圈,又有了點收穫,原來老外也有這方面的需求,這個老外完全是自己用代碼實現的,牛,贊一個先。

主要實現的類:

using System;
using System.Collections.Generic;
using System.Text;

namespace AutoComputer
{
    
class VariFormel
    
{
        
private string vars = "", zc;
        
private double[] values = new double[10];
        
private int pos, klammer, ebene;
        
private double res;
        
private bool fehler = false;

        
/// <summary>
        
/// Rechnet eine Formel aus
        
/// </summary>
        
/// <param name="formel">Der text mit der Formel</param>
        
/// <param name="result">Variable, die das Ergebnis erh鋖t</param>
        
/// <returns>Erfolg der Funktion</returns>

        public bool Neu(string formel, out double result)
        
{
            
if (formel == ""
            
{ result = 0.0return false; }
            fehler 
= false;
            result 
= Zuteilung(formel);
            
return !fehler;
        }


        
/// <summary>
        
/// Rekursive Hauptprozedur, die die Formel ausrechnet
        
/// </summary>
        
/// <param name="Op">Der Text mit der Formel</param>
        
/// <returns>Das Ergebnis der Formel oder 0 bei Fehlern</returns>

        private double Zuteilung(string Op)
        
{
            
if (Op.Length == 0goto fehl;
            
if (Op.StartsWith("("&& GetKlammer(Op, 0== Op.Length - 1
                Op 
= Op.Substring(1, Op.Length - 2);
            
if (double.TryParse(Op, System.Globalization.NumberStyles.Float,nullout res)) 
                
return res;
            
if (Op.Length == 2 && Op == "PI"return Math.PI;
            
if (Op.Length == 1 && TryVariable(Op, out res)) return res;
            
if (Op.Length > 4 && Op.Substring(31== "(")
            
{
                pos 
= GetKlammer(Op, 3);
                
if (pos != Op.Length - 1goto next;
                zc 
= Op.Substring(4, pos - 4);
                
switch (Op.Substring(03))
                
{
                    
case "sqr"return Math.Sqrt(Zuteilung(zc));
                    
case "sin"return Math.Sin(Math.PI * Zuteilung(zc) / 180);
                    
case "cos"return Math.Cos(Math.PI * Zuteilung(zc) / 180);
                    
case "tan"return Math.Tan(Math.PI * Zuteilung(zc) / 180);
                    
case "log"return Math.Log10(Zuteilung(zc));
                    
case "abs"return Math.Abs(Zuteilung(zc));
                    
case "fac"return Faculty(Zuteilung(zc));
                }

            }

        next:
            pos 
= 0; ebene = 6; klammer = 0;
            
for (int i = Op.Length - 1; i > -1; i--)
            
{
                
switch (Op.Substring(i, 1))
                
{
                    
case "(": klammer++break;
                    
case ")": klammer--break;
                    
case "+"if (klammer == 0 && ebene > 0{ pos = i; ebene = 0; } break;
                    
case "-"if (klammer == 0 && ebene > 1{ pos = i; ebene = 1; } break;
                    
case "*"if (klammer == 0 && ebene > 2{ pos = i; ebene = 2; } break;
                    
case "%"if (klammer == 0 && ebene > 3{ pos = i; ebene = 3; } break;
                    
case "/"if (klammer == 0 && ebene > 4{ pos = i; ebene = 4; } break;
                    
case "^"if (klammer == 0 && ebene > 5{ pos = i; ebene = 5; } break;
                }

            }

            
if (pos == 0 || pos == Op.Length - 1goto fehl;
            zc 
= Op.Substring(pos, 1);
            
string t1, t2;
            t1 
= Op.Substring(0, pos);
            t2 
= Op.Substring(pos + 1, Op.Length - (pos + 1));
            
switch (zc)
            
{
                
case "+"return Zuteilung(t1) + Zuteilung(t2);
                
case "-"return Zuteilung(t1) - Zuteilung(t2);
                
case "*"return Zuteilung(t1) * Zuteilung(t2);
                
case "/"return Zuteilung(t1) / Zuteilung(t2);
                
case "%"return Math.IEEERemainder(Zuteilung(t1), Zuteilung(t2));
                
case "^"return Math.Pow(Zuteilung(t1), Zuteilung(t2));
            }

        fehl:
            fehler 
= true;
            
return 0.0;
        }

        
/// <summary>
        
/// Sucht zu einer ge鰂fneten Klammer die Position der entsprechend schlie遝nden Klammer
        
/// </summary>
        
/// <param name="Op">Der zu 黚erpr黤ende Text</param>
        
/// <param name="start">Position der er鰂fnenden Klammer</param>
        
/// <returns>Position der schlie遝nden Klammer, oder START, wenn keine vorhanden</returns>

        private int GetKlammer(string Op, int start)
        
{
            
int res = start;
            
for (int i = start; i < Op.Length; i++)
            
{
                
switch (Op.Substring(i, 1))
                
{
                    
case "(": klammer++break;
                    
case ")": klammer--break;
                }

                
if (klammer == 0{ res = i; break; }
            }

            
return res;
        }

        
/// <summary>
        
/// Pr黤t, ob der Text eine Variable bezeichnet und schreibt den Wert in eine Variable
        
/// </summary>
        
/// <param name="Op">Der zu 黚erpr黤ende Text</param>
        
/// <param name="wert">Adresse der Variable, die den Wert erhalten soll</param>
        
/// <returns>TRUE, wenn eine Variable gefunden wurde</returns>

        private bool TryVariable(string Op, out double wert)
        
{
            
int i = vars.IndexOf(Op);
            
if (i != -1)
            
{
                wert 
= values[i];
                
return true;
            }

            
else
            
{
                wert 
= 0.0;
                
return false;
            }

        }

        
private double Faculty(double number)
        
{
            
if (double.IsInfinity(number) ||
                
double.IsNaN(number) ||
                number 
< 0.0 ||
                number 
% 1.0 != 0return double.NaN;
            
double res = 1.0;
            
for (int i = 0; i < number; i++)
                res 
*= (double)(i + 1);
            
return res;
        }

    }

}


調用部分:
[System.Runtime.InteropServices.DllImport("user32.dll")]
        
private static extern int MessageBeep(int wType);
        
private const int MB_ICONASTERISK = 0x40;

        
private VariFormel fml = new VariFormel();

        
private void btnCalc_Click(object sender, EventArgs e)
        
{
            Calculate();
        }

        
private void Calculate()
        
{
            
double res;
            
if (!fml.Neu(tbFormel.Text, out res))
            
{
                lblResult.Text 
= "Die Formel enth鋖t Fehler";
                MessageBeep(MB_ICONASTERISK);
            }

            
else
                lblResult.Text 
= res.ToString();
        }

由於比較急,註釋部分還沒來得及翻譯,先講究着看吧,呵呵
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章