程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 動態地生成用戶輸入的函數表達式(C#)

動態地生成用戶輸入的函數表達式(C#)

編輯:C#入門知識

動態地生成用戶輸入的函數表達式(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,所以說作者斷言在該處肯定會得到一個錯誤的解。
下面就是源程序:
align=top// ExpressionTest.cs - 動態生成數學表達式並計算其值的測試程序
align=top// 編譯方法: csc ExpressionTest.cs Expression.cs
align=top
align=topusing System;
align=topusing Skyiv.Util;
align=top
align=topnamespace Skyiv.Test
align=top{
align=top class ExpressionTest
align=top {
align=top static void Main(string [] args)
align=top {
align=top try
align=top {
align=top if (args.Length > 0)
align=top {
align=top Console.WriteLine(f(x): {0}, args[0]);
align=top Expression expression = new Expression(args[0]);
align=top for (int i = 1; i < args.Length; i++)
align=top {
align=top double x = double.Parse(args[i]);
align=top Console.WriteLine(f({0}) = {1}, x, expression.Compute(x));
align=top }
align=top }
align=top else Console.WriteLine(Usage: ExpressionTest expression [ parameters height=20 ]);
align=top }
align=top catch (Exception ex)
align=top {
align=top Console.WriteLine(錯誤: + ex.Message);
align=top }
align=top }
align=top }
align=top}
align=top align=top// Expression.cs - 動態生成數學表達式並計算其值
align=top// 表達式使用 C# 語法,可帶一個的自變量(x)。
align=top// 表達式的自變量和值均為(double)類型。
align=top// 使用舉例:
align=top// Expression expression = new Expression(Math.Sin(x));
align=top// Console.WriteLine(expression.Compute(Math.PI / 2));
align=top// expression = new Expression(double u = Math.PI - x; +
align=top// double pi2 = Math.PI * Math.PI; +
align=top// return 3 * x * x + Math.Log(u * u) / pi2 / pi2 + 1;);
align=top// Console.WriteLine(expression.Compute(0));
align=top
align=topusing System;
align=topusing System.CodeDom.Compiler;
align=topusing Microsoft.CSharp;
align=topusing System.Reflection;
align=topusing System.Text;
align=top
align=topnamespace Skyiv.Util
align=top{
align=top sealed class Expression
align=top {
align=top object instance;
align=top MethodInfo method;
align=top
align=top public Expression(string expression)
align=top {
align=top if (expression.IndexOf(return) < 0) expression = return + expression + ;;
align=top string className = Expression;
align=top string methodName = Compute;
align=top CompilerParameters p = new CompilerParameters();
align=top p.GenerateInMemory = true;
align=top CompilerResults cr = new CSharpCodeProvider().CompileAssemblyFromSource(p, string.
align=top Format(using System;sealed class {0}{{public double {1}(double x){{{2}}}}},
align=top className, methodName, expression));
align=top if(cr.Errors.Count > 0)
align=top {
align=top string msg = Expression( + expression + ): ;
align=top foreach (CompilerError err in cr.Errors) msg += err.ToString() + ;
align=top throw new Exception(msg);
align=top }
align=top instance = cr.CompiledAssembly.CreateInstance(className);
align=top method = instance.GetType().GetMethod(methodName);
align=top }
align=top
align=top public double Compute(double x)
align=top {
align=top return (double)method.Invoke(instance, new object [] { x });
align=top }
align=top }
align=top}
align=top 在這裡向 CSDN 論壇的“LoveCherry(論成敗,人生豪邁;大不了,重頭再來!^_^) ”表示感謝,我的程序就是在他的程序的基礎上發展而來的。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved