使用 C# 代码计算数学表达式

devtools/2024/12/28 2:43:10/

此程序展示了如何使用 C# 代码来计算数学表达式。该程序以以下代码开始。

此代码声明了一个Dictionary,稍后将使用它来保存变量。(例如,如果用户想要 A = 10、B = 3 和 Pi = 3.14159265。)

然后它定义了一个Precedence枚举来表示运算符的优先级。例如,乘法的优先级高于加法。

单击“Evaluate”按钮时,程序会复制您输入到“ Primatives Dictionary”中的任何基元,然后调用EvaluateExpression方法,该方法会执行所有有趣的工作。该方法很长,因此我将分段描述。

// Stores user-entered primitives like X = 10.
private Dictionary<string, string> Primatives;private enum Precedence
{None = 11,Unary = 10,     // Not actually used.Power = 9,      // We use ^ to mean exponentiation.Times = 8,Div = 7,Modulus = 6,Plus = 5,
}
// Evaluate the expression.
private double EvaluateExpression(string expression)
{int best_pos = 0;int parens = 0;// Remove all spaces.string expr = expression.Replace(" ", "");int expr_len = expr.Length;if (expr_len == 0) return 0;// If we find + or - now, then it's a unary operator.bool is_unary = true;// So far we have nothing.Precedence best_prec = Precedence.None;// Find the operator with the lowest precedence.// Look for places where there are no open// parentheses.for (int pos = 0; pos < expr_len; pos++){// Examine the next character.string ch = expr.Substring(pos, 1);// Assume we will not find an operator. In// that case, the next operator will not// be unary.bool next_unary = false;if (ch == " "){// Just skip spaces. We keep them here// to make the error messages easier to}else if (ch == "("){// Increase the open parentheses count.parens += 1;// A + or - after "(" is unary.next_unary = true;}else if (ch == ")"){// Decrease the open parentheses count.parens -= 1;// An operator after ")" is not unary.next_unary = false;// if parens < 0, too many )'s.if (parens < 0)throw new FormatException("Too many close parentheses in '" +expression + "'");}else if (parens == 0){// See if this is an operator.if ((ch == "^") || (ch == "*") ||(ch == "/") || (ch == "\\") ||(ch == "%") || (ch == "+") ||(ch == "-")){// An operator after an operator// is unary.next_unary = true;// See if this operator has higher// precedence than the current one.switch (ch){case "^":if (best_prec >= Precedence.Power){best_prec = Precedence.Power;best_pos = pos;}break;case "*":case "/":if (best_prec >= Precedence.Times){best_prec = Precedence.Times;best_pos = pos;}break;case "%":if (best_prec >= Precedence.Modulus){best_prec = Precedence.Modulus;best_pos = pos;}break;case "+":case "-":// Ignore unary operators// for now.if ((!is_unary) &&best_prec >= Precedence.Plus){best_prec = Precedence.Plus;best_pos = pos;}break;} // End switch (ch)} // End if this is an operator.} // else if (parens == 0)is_unary = next_unary;} // for (int pos = 0; pos < expr_len; pos++)

该方法的这一部分用于查找表达式中优先级最低的运算符。为此,它只需循环遍历表达式,检查其运算符字符,并确定它们的优先级是否低于先前找到的运算符。

下面的代码片段显示了下一步。

    // If the parentheses count is not zero,// there's a ) missing.if (parens != 0){throw new FormatException("Missing close parenthesis in '" +expression + "'");}// Hopefully we have the operator.if (best_prec < Precedence.None){string lexpr = expr.Substring(0, best_pos);string rexpr = expr.Substring(best_pos + 1);switch (expr.Substring(best_pos, 1)){case "^":return Math.Pow(EvaluateExpression(lexpr),EvaluateExpression(rexpr));case "*":returnEvaluateExpression(lexpr) *EvaluateExpression(rexpr);case "/":returnEvaluateExpression(lexpr) /EvaluateExpression(rexpr);case "%":returnEvaluateExpression(lexpr) %EvaluateExpression(rexpr);case "+":returnEvaluateExpression(lexpr) +EvaluateExpression(rexpr);case "-":returnEvaluateExpression(lexpr) -EvaluateExpression(rexpr);}}

如果括号未闭合,该方法将引发异常。否则,它会使用优先级最低的运算符作为分界点,将表达式拆分成多个部分。然后,它会递归调用自身来评估子表达式,并使用适当的操作来合并结果。

例如,假设表达式为 2 * 3 + 4 * 5。那么优先级最低的运算符是 +。该函数将表达式分解为 2 * 3 和 4 * 5,并递归调用自身来计算这些子表达式的值(得到 6 和 20),然后使用加法将结果合并(得到 26)。

以下代码显示该方法如何处理函数调用。

    // if we do not yet have an operator, there// are several possibilities://// 1. expr is (expr2) for some expr2.// 2. expr is -expr2 or +expr2 for some expr2.// 3. expr is Fun(expr2) for a function Fun.// 4. expr is a primitive.// 5. It's a literal like "3.14159".// Look for (expr2).if (expr.StartsWith("(") & expr.EndsWith(")")){// Remove the parentheses.return EvaluateExpression(expr.Substring(1, expr_len - 2));}// Look for -expr2.if (expr.StartsWith("-")){return -EvaluateExpression(expr.Substring(1));}// Look for +expr2.if (expr.StartsWith("+")){return EvaluateExpression(expr.Substring(1));}// Look for Fun(expr2).if (expr_len > 5 & expr.EndsWith(")")){// Find the first (.int paren_pos = expr.IndexOf("(");if (paren_pos > 0){// See what the function is.string lexpr = expr.Substring(0, paren_pos);string rexpr = expr.Substring(paren_pos + 1,expr_len - paren_pos - 2);switch (lexpr.ToLower()){case "sin":return Math.Sin(EvaluateExpression(rexpr));case "cos":return Math.Cos(EvaluateExpression(rexpr));case "tan":return Math.Tan(EvaluateExpression(rexpr));case "sqrt":return Math.Sqrt(EvaluateExpression(rexpr));case "factorial":return Factorial(EvaluateExpression(rexpr));// Add other functions (including// program-defined functions) here.}}}

此代码检查表达式是否以 ( 开头并以 结尾。如果是,则删除这些括号并计算表达式的其余部分。

接下来,代码确定表达式是否以一元 + 或 - 运算符开头。如果是,程序将计算不带运算符的表达式,如果运算符为 -,则对结果取反。

然后,代码会查找SinCosFactorial等函数。如果找到,它会调用该函数并返回结果。(下载示例以查看Factorial函数。)您可以类似地添加其他函数。

以下代码显示了该方法的其余部分。

    // See if it's a primitive.if (Primatives.ContainsKey(expr)){// Return the corresponding value,// converted into a Double.try{// Try to convert the expression into a value.return double.Parse(Primatives[expr]);}catch (Exception){throw new FormatException("Primative '" + expr +"' has value '" +Primatives[expr] +"' which is not a Double.");}}// It must be a literal like "2.71828".try{// Try to convert the expression into a Double.return double.Parse(expr);}catch (Exception){throw new FormatException("Error evaluating '" + expression +"' as a constant.");}
}

如果表达式仍未求值,则它必须是您在文本框中输入的原始值或数值。代码将检查原始字典以查看表达式是否存在。如果值在字典中,则代码获取其值,将其转换为双精度值,然后返回结果。


http://www.ppmy.cn/devtools/145590.html

相关文章

原点安全再次入选信通院 2024 大数据“星河”案例

近日&#xff0c;中国信息通信研究院和中国通信标准化协会大数据技术标准推进委员会&#xff08;CCSA TC601&#xff09;共同组织开展的 2024 大数据“星河&#xff08;Galaxy&#xff09;”案例征集活动结果正式公布。由工银瑞信基金管理有限公司、北京原点数安科技有限公司联…

“信任构建”:网上购物商城的用户评价与信誉系统

2 相关技术 2.1 SSM框架介绍 本课题程序开发使用到的框架技术&#xff0c;英文名称缩写是SSM&#xff0c;在JavaWeb开发中使用的流行框架有SSH、SSM、SpringMVC等&#xff0c;作为一个课题程序采用SSH框架也可以&#xff0c;SSM框架也可以&#xff0c;SpringMVC也可以。SSH框架…

iOS AccentColor 和 Color Set

AccentColor 和 Color Set 都是 Xcode 中用于颜色管理的功能&#xff0c;它们适用于不同的开发场景和需求。以下是它们的区别和应用场景分析&#xff1a; 1. AccentColor&#xff08;强调色&#xff09; 1.1 概念&#xff1a; • AccentColor 是在 Xcode 12 中引入的&#xf…

编码转换(实例)

前四期 字符编码(四)-CSDN博客 实现二进制、八进制、十进制、十六进制互换转换&#xff1a; Java编码转换 import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);System.out.println("欢迎…

R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)

1. 上下标 # 注意y轴标签文字 library(ggplot2) ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))2. 希腊字母&#xff0c;如alpha ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))ggtitle(expression(alpha))…

ThinkPHP接入PayPal支付

ThinkPHP 5接入PayPal 支付&#xff0c;PayPal的流程是服务器请求Paypal的接口下单&#xff08;需要传订单id/支付成功的重定向地址/支付失败的重定向地址&#xff09;&#xff0c;接会返回一个支付地址&#xff0c;项目服务器把地址返给用户&#xff0c;用户打开链接登录Paypa…

C语言:指针4(常量指针和指针常量及动态内存分配)

常量指针与指针常量 常量&#xff1a;分为字面量和只读常量&#xff0c;字面量就是我们平时直接操作的量&#xff1a; printf("%d\n",12);/printf("%s\n","hello");只读常量使用关键字 const 修饰&#xff0c;凡是被这个关键字修饰 的变量&…

Python趣味小游戏 加解密

生活中&#xff0c;一直有烦人的人偷看信息&#xff0c;所以我们可以把信息加密解密&#xff01; 加密程序 text input() s "" i0 while i < len (text):ctext[i]if a < c < w or A < c < W:c chr(ord(c)3)elifx < c < z or X< c < Z…