Matlab可以对数学公式进行求导操作,这里用F#实现一个简单的表达式求导推理。首先还是定义一个自定义的Expr数据类型:
typeExpr=|CstFoffloat|Varofstring|AddofExpr*Expr// +|SubofExpr*Expr// -|MulofExpr*Expr// *|DivofExpr*Expr// / |PowofExpr*Expr// ^ |SinofExpr|CosofExpr|NegofExpr
定义一个递归的求导函数diff,由于求导的规则比较多,这里就简单的实现几个场景的求导公式:
letrecdiffe=matchewith|CstFf->CstF0.0|Varx->CstF1.0|Add(CstFa, Varx) ->CstF1.0|Add(e1, e2) ->Add(diffe1, diffe2) |Sub(e1, e2) ->Sub(diffe1, diffe2) |Mul(CstFa, Varx) ->CstFa|Mul(e1, e2) ->Mul(diffe1, diffe2) |Pow(Varx,CstFa) ->Mul(CstFa,Pow(Varx,CstF (a-1.))) |Pow(e1,e2) ->Mul(e2,Pow(e1, Sub(e2,CstF1.))) |Sin(e1) ->Mul(Cos(e1),diffe1) |Cos(e1) ->Mul(Neg(Sin(e1)),diffe1) |Neg(e1) ->Neg(diffe1) |e->e ;;
为了更到的输出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";;
严格来讲,每个操作的前后用()进行分组应该更加严谨,但是过多的()嵌套会让数学表达式不容易理解。但,关于括号的嵌套化简问题,还需要一定的工作才能工作,这里先不进行处理。下面定义一个求导示例:
lete1=Sin(Sub(Pow(Var"x", CstF3.0), Var"x")) ;; lete2=diffe1;; printExpr2e2;;
执行如上代码,则输出如下图所示:
这与网上的求导工具(https://zh.numberempire.com/derivativecalculator.php)求出的一致: