【摘要】 用F#实现一个简单的表达式求导推理: diff(sin(x^3-x)) => cos(x^3-x) * (3*x^2-1)
Matlab可以对数学公式进行求导操作,这里用F#实现一个简单的表达式求导推理。首先还是定义一个自定义的Expr数据类型:
type Expr =
| CstF of float
| Var of string
| Add of Expr * Expr // +
| Sub of Expr * Expr // -
| Mul of Expr * Expr // *
| Div of Expr * Expr // /
| Pow of Expr * Expr // ^
| Sin of Expr
| Cos of Expr
| Neg of Expr
定义一个递归的求导函数diff,由于求导的规则比较多,这里就简单的实现几个场景的求导公式:
let rec diff e =
match e with
| CstF f -> CstF 0.0
| Var x -> CstF 1.0
| Add(CstF a, Var x) -> CstF 1.0
| Add(e1, e2) -> Add(diff e1, diff e2)
| Sub(e1, e2) -> Sub(diff e1, diff e2)
| Mul(CstF a, Var x) -> CstF a
| Mul(e1, e2) -> Mul(diff e1, diff e2)
| Pow(Var x,CstF a) -> Mul(CstF a,Pow(Var x,CstF (a - 1.)))
| Pow(e1,e2) -> Mul(e2,Pow(e1, Sub(e2,CstF 1.)))
| Sin(e1) -> Mul(Cos(e1),diff e1)
| Cos(e1) -> Mul(Neg(Sin(e1)),diff e1)
| Neg(e1) -> Neg(diff e1)
| e -> e ;;
为了更到的输出DSL到控制台,定义一个打印表达式的函数:
let rec printExpr2 e =
match e with
| CstF f -> string f
| Var x -> x
| Add(e1 , e2) -> "(" + (printExpr2 e1) + "+" + (printExpr2 e2) + ")"
| Sub(e1 , e2) -> "(" + (printExpr2 e1) + "-" + (printExpr2 e2) + ")"
| Mul(e1 , e2) -> "(" + (printExpr2 e1) + "*" + (printExpr2 e2) + ")"
| Div(e1 , e2) -> "(" + (printExpr2 e1) + "/" + (printExpr2 e2) + ")"
| Pow(e1 , e2) -> "(" + (printExpr2 e1) + "^" + (printExpr2 e2) + ")"
| Sin(e1) -> "sin(" + (printExpr2 e1) + ")"
| Cos(e1) -> "cos(" + (printExpr2 e1) + ")"
| Neg(e1) -> "-(" + (printExpr2 e1) + ")"
| _ -> failwith "unknown operation";;
严格来讲,每个操作的前后用()进行分组应该更加严谨,但是过多的()嵌套会让数学表达式不容易理解。但,关于括号的嵌套化简问题,还需要一定的工作才能工作,这里先不进行处理。下面定义一个求导示例:
let e1 = Sin(Sub(Pow(Var "x", CstF 3.0), Var "x")) ;;
let e2 = diff e1;;
printExpr2 e2;;
执行如上代码,则输出如下图所示:
这与网上的求导工具(https://zh.numberempire.com/derivativecalculator.php)求出的一致:
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END