动态地生成用户输入的函数表达式(C#)

我在一篇随笔“画函数图形的C#程序,兼论一个病态函数”中提到:
这个画函数图形的C#程序有一个严重的缺点,就是函数表达式是直接写的源程序中的,不能象SciLab和Matlab那样交互式地输入。不知道用 System.Reflection.Emit.ILGenerator 类能不能动态地生成用户输入的函数表达式?“空间/IV”在该随笔的评论中指出:

关于动态地生成用户输入的函数表达式, 看看下面这个帖子说不定有帮助:

http://community.csdn.net/Expert/topic/4169/4169185.xml经研究,我写了一个动态地生成用户输入的函数表达式的类(class Expression),表达式使用 C#
语法,可带一个的自变量(x),其自变量和值均为“double”类型。下面是测试程序的运行结果:

C> ExpressionTest

Usage: ExpressionTest expression [ parameters ... ]

C> ExpressionTest Math.PI*Math.E 0

f(x): Math.PI*Math.E

f(0) = 8.53973422267357

C> ExpressionTest Math.Pow(2,x) 0 10 49 50 1024 -1 -1024

f(x): Math.Pow(2,x)

f(0) = 1

f(10) = 1024

f(49) = 562949953421312

f(50) = 1.12589990684262E+15

f(1024) = 正无穷大

f(-1) = 0.5

f(-1024) = 5.562684646268E-309

C> ExpressionTest "double u = Math.PI - x; double pi2 = Math.PI * Math.PI; return 3 * x * x + Math.Log(u * u) / pi2 / pi2 + 1;" 3.13 3.14 3.15 3.16 3.1416

f(x): double u = Math.PI - x; double pi2 = Math.PI * Math.PI; return 3 * x * x + Math.Log(u * u) / pi2 / pi2 + 1;

f(3.13) = 30.2991811562164

f(3.14) = 30.44652582187

f(3.15) = 30.6693849404716

f(3.16) = 30.8747746902426

f(3.1416) = 30.3662371931734

其中最后一个例子就是我在随笔“画函数图形的C#程序,兼论一个病态函数”的下列函数的计算结果:

实际上这个病态函数是《C数值算法(第二版)》第三章“内插法和外推法”中提到的:

---------------------------------------------------------------------------

可以很容易地构造一些病态函数使内插法失败。例如,考虑函数

f(x) = 3 * x2 + π-4 * ln[(π-x)2] + 1

它除了 x = π 之外都有定义,而 x = π 时无定义,其它情况,值有正有负。而这函数在任何基于数值 x = 3.13, 3.14, 3.15, 3.16 的插值法,都肯定在 x = 3.1416 处得到一个错误的解,尽管通过这五个点所画的曲线确实相当平滑!(用计算器试试看。)

---------------------------------------------------------------------------

可以看出,而这函数在任何基于数值 x = 3.13, 3.14, 3.15, 3.16 的插值法,在 x = 3.1416 处得到的解肯定在 30.44652582187 和 30.6693849404716 之间,但实际的解应该是 30.3662371931734,所以说作者断言在该处肯定会得到一个错误的解。

下面就是源程序:

// ExpressionTest.cs - 动态生成数学表达式并计算其值的测试程序

// 编译方法: csc ExpressionTest.cs Expression.cs

using System;

using Skyiv.Util;

namespace Skyiv.Test

{

  class ExpressionTest

  {

    static void Main(string [] args)

    {

      try

      {

        if (args.Length > 0)

        {

          Console.WriteLine("f(x): {0}", args[0]);

          Expression expression = new Expression(args[0]);

          for (int i = 1; i < args.Length; i++)

          {

            double x = double.Parse(args[i]);

            Console.WriteLine("f({0}) = {1}", x, expression.Compute(x));

          }

        }

        else Console.WriteLine("Usage: ExpressionTest expression [ parameters  ]");

      }

      catch (Exception ex)

      {

        Console.WriteLine("错误: " + ex.Message);

      }

    }

  }

}

// Expression.cs - 动态生成数学表达式并计算其值

// 表达式使用 C# 语法,可带一个的自变量(x)。

// 表达式的自变量和值均为(double)类型。

// 使用举例:

//   Expression expression = new Expression("Math.Sin(x)");

//   Console.WriteLine(expression.Compute(Math.PI / 2));

//   expression = new Expression("double u = Math.PI - x;" +

//     "double pi2 = Math.PI * Math.PI;" +

//     "return 3 * x * x + Math.Log(u * u) / pi2 / pi2 + 1;");

//   Console.WriteLine(expression.Compute(0));

using System;

using System.CodeDom.Compiler;

using Microsoft.CSharp;

using System.Reflection;

using System.Text;

namespace Skyiv.Util

{

  sealed class Expression

  {

    object instance;

    MethodInfo method;

    public Expression(string expression)

    {

      if (expression.IndexOf("return") < 0) expression = "return " + expression + ";";

      string className = "Expression";

      string methodName = "Compute";

      CompilerParameters p = new CompilerParameters();

      p.GenerateInMemory = true;

      CompilerResults cr = new CSharpCodeProvider().CompileAssemblyFromSource(p, string.

        Format("using System;sealed class {0}{{public double {1}(double x){{{2}}}}}",

        className, methodName, expression));

      if(cr.Errors.Count > 0)

      {

        string msg = "Expression(\"" + expression + "\"): \n";

        foreach (CompilerError err in cr.Errors) msg += err.ToString() + "\n";

        throw new Exception(msg);

      }

      instance = cr.CompiledAssembly.CreateInstance(className);

      method = instance.GetType().GetMethod(methodName);

    }

    public double Compute(double x)

    {

      return (double)method.Invoke(instance, new object [] { x });

    }

  }

}

在这里向 CSDN 论坛的“LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^) ”表示感谢,我的程序就是在他的程序的基础上发展而来的。

版权声明:本文为博主http://www.zuiniusn.com原创文章,未经博主允许不得转载。

时间: 2024-10-29 19:08:39

动态地生成用户输入的函数表达式(C#)的相关文章

用户输入校对函数

//用户输入校对函数 //姓名校对 function checkename(str){ var m_name = /^[\u4E00-\u9FA5]{2,7}$/; return m_name.test(str); } //电子邮箱校对 function checkemail(str){ var m_email = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; return m_email.test(str)

python入门学习--语句、获取用户输入、函数

1.语句 1.1 语句和表达式有什么区别呢?表达式就是某件事情,而语句是做某件事情(即告诉计算机做什么).比如2*2是4,而print2*2则是打印4 1.2 if语句 当条件为假时,什么都没发生:当条件为真时,后面的语句(上图为print语句)被执行.注:在交互式解释器内使用if语句,需要按两次回车,if语句才会执行 2.获取用户输入 python提示符(>>>)后面的语句可以算作一个完整的程序的组成部分了,输入的值由用户提供,而程序就会打印出输入的两个数的乘积1428.在编写程序的时

Python从菜鸟到高手(6):获取用户输入、函数与注释

1. 获取用户输入   要编写一个有实际价值的程序,就需要与用户交互.当然,与用户交互有很多方法,例如,GUI(图形用户接口)就是一种非常好的与用户交互的方式,不过我们先不讨论GUI的交互方式,本节会采用一种原始,但很有效的方式与用户交互,这就是命令行交互方式,也就是说,用户通过命令行方式输入数据,程序会读取这些数据,并做进一步的处理.   从命令行接收用户的输入数据,需要使用input函数.input函数接收一个字符串类型的参数,用于作为输入的提示.input函数的返回值就是用户在命令行中录入

通过函数实现打印*号组成的直角三角形,函数要求传入行数即可。在main 方法中,通过用户输入得到行数,然后调用函数做打印。

#include <stdio.h> /* 1.通过函数实现打印*号组成的直角三角形,函数要求传入行数即可.在main方法中,通过用户输入得到行数,然后调用函数做打印.三角形样式:********************* */ int sanjiao(int hang){ int i; int j; for(i = 0; i < hang;i++) { for(j = 0;j <i+1;j++) { printf("*"); } printf("\n

用三个函数分别实现求三角形,正方形,圆形面积(所有底高半径都由用户 输入);在主函数中,通过用户不同的选择分别进行调用;

/*2.用三个函数分别实现求三角形,正方形,圆形面积(所有底高半径都由用户输入):在主函数中,通过用户不同的选择分别进行调用:*/ #include <stdio.h>#define P 3.14double sanjiao(double di,double gao){ double mianji = (di * gao)/2 ; return mianji;} double zhengfangxing(double bian){ double mianji2 = bian*bian; ret

编程题:用函数实现,用户输入年月日,来计算出该日期为当年第几天?

#include<stdio.h> /*函数is_leap_year()的返回值是判断该年是否闰年*/ int is_leap_year(int year) { int leap; if(year%4==0&&year%100!=0||year%400==0) leap=1; else leap=0; return leap; } /*函数len_of_month()的返回值为某年year的某月month的天数*/ int len_of_month(int year,int m

作业--用户输入数字0-100,判断成绩,用函数

  1 #作业 2 # 作业: 3 # 用户输入数字0-100 4 # 程序判断: 5 # 数字>90,成绩为A 6 # 数字>80,成绩为B 7 # 数字>70,成绩为C 8 # 数字<60,成绩为D 9 # 尝试用函数完成? 10 11 def score(name): 12 print("welcome to %s".center(50,"-")%(name.upper())) 13 14 while True: 15 choice =

Thinkphp+AJAX动态验证用户输入是否合法

遇到用户注册等情况时,如果等用户输入所有信息,点击注册按钮提交后,再验证输入是否正确,体验很不好,而且很浪费用户的时间,增加注册成本,这里提供一个例子,演示了怎么使用ajax进行单步验证,使用thinkphp 3.2框架,环境WAMPServer 2.4,版本PHP 5.4.16+ Apache 2.4.4+ MySql 5.6.12 一.数据库设计: 数据库名 thinkphp 表名 tp_user 其中tp_是表前缀,可以在config.php中定义,操作表的时候只用user就行 二.页面设

python学习:注释、获取用户输入、字符串拼接、运算符、表达式

注释 #为单行注释'''三个单引号(或者"""三个双引号)为多行注释,例如'''被注释的内容''' 获取用户输入 input() input 接受的所有数据都是字符串,即便你输入的是数字,但依然会被当成字符串来处理.把数据转成字符串用STR(被转的数据):把字符串转成数据用int(被转的字符串). 字符串拼接 "abc"+"def"="abcdef"            "abc","