前面一篇博文,介绍了F#对数学表达式进行求导运算,这里再介绍一下如何用F#对数学表达式求积分。求符号积分比求导要复杂一点,其复杂不在于原理,而在于求导的规则少,而求积分的规则非常多,要想相对全面的涵盖是比较难的。
这里只是探索一个求积分的思路,而不会实现一个功能完备的积分引擎。首先还是定义一个数据类型:
typeExpr=|CstFoffloat|Varofstring|AddofExpr*Expr// +|SubofExpr*Expr// -|MulofExpr*Expr// *|DivofExpr*Expr// / |PowofExpr*Expr// ^ |SinofExpr|CosofExpr|NegofExpr
再次,给出一个包含少数积分规则的求积分函数:
letrecintfe=matchewith|CstFf->Mul(CstFf, Var"x") |Varx->Mul(CstF0.5, Pow(Varx,CstF2.)) |Add(e1, e2) ->Add(intfe1, intfe2) |Sub(e1, e2) ->Sub(intfe1, intfe2) |Pow(Varx,CstFa) ->Mul(CstF (1./(a+1.)),Pow(Varx,CstF (a+1.))) |e->e
这里主要就是最后一条,即 x ^ a 求积分为 x^(a+1)/(a+1) 。同样的,给出DSL字符串输出的函数:
letrecprintExpr2e=matchewith|CstFf->stringf|Varx->x|Add(e1 , e2) ->"("+ (printExpr2e1) +"+"+ (printExpr2e2) +")"|Sub(e1 , e2) ->"("+ (printExpr2e1) +"-"+ (printExpr2e2) +")"|Mul(e1 , e2) ->"("+ (printExpr2e1) +"*"+ (printExpr2e2) +")"|Div(e1 , e2) ->"("+ (printExpr2e1) +"/"+ (printExpr2e2) +")"|Pow(e1 , e2) ->"("+ (printExpr2e1) +"^"+ (printExpr2e2) +")"|Sin(e1) ->"sin("+ (printExpr2e1) +")"|Cos(e1) ->"cos("+ (printExpr2e1) +")"|Neg(e1) ->"-("+ (printExpr2e1) +")"|_->failwith"unknown operation";;
最后,计算一下数学公式(x^3)-x的积分值:
lete1=Sub(Pow(Var"x", CstF3.0), Var"x");; printExpr2e1+" => "+printExpr2 (intfe1) ;;
运行此示例,输出结果如下:
即 (x^3)-x的积分表达式为: 0.25*x^4 - 0.5*x^2 。