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)求出的一緻: