我如何表示不完整的数学函数?
我需要做(x - constant)
然后
(x - constant)*(x - another) => (x^2 - x * constant - x * another + constant * another)
等等。
我正在尝试制作拉格朗日插值程序(找到某些点的函数) 所以我需要从一组已知的值中创建一个我可以看到的函数(print或者其他东西)。 抱歉,如果混淆。
答案 0 :(得分:4)
如果您想按照here
所述实施拉格朗日插值然后这是直接翻译成F#:
let LagrangeInterpol (points : (Double*Double)[]) x =
let indizes = [0..points.Length-1]
let p j =
indizes
|> List.map (fun k ->
if k <> j
then (x - fst points.[k])
/ (fst points.[j] - fst points.[k])
else 1.0)
|> List.fold (*) 1.0
indizes |> List.sumBy (fun j -> p j * snd points.[j])
这是一个简单的测试会话:
> let points = [|0.0,0.0; 1.0,2.0; 2.0,3.0|];;
val points : (float * float) [] = [|(0.0, 0.0); (1.0, 2.0); (2.0, 3.0)|]
> let f = LagrangeInterpol points;;
val f : (Double -> float)
> f 0.0;;
val it : float = 0.0
> f 1.0;;
val it : float = 2.0
> f 2.0;;
val it : float = 3.0
所以我希望我没有犯任何重大错误。
请注意,我没有在这里做任何性能优化的efford - 这应该足以绘制图表或在两者之间获得一些值。
这有点棘手 - 你可以试着想出系数的组合公式,或者(比如我这里)是数学上懒惰的,只需用足够的算子实现Polynom-Type:
type Polynom =
Poly of float list with
override p.ToString () =
match p with
| Poly coefs ->
System.String.Join (" + ", coefs |> List.mapi (fun i c -> sprintf "%AX^%d" c i))
static member Const c = Poly [c]
static member Zero = Polynom.Const 0.0
static member One = Polynom.Const 1.0
static member X = Poly [0.0; 1.0]
static member (+) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a+b)
|> Poly
static member (-) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a-b)
|> Poly
static member (*) (f : float, Poly cs2) : Polynom =
cs2
|> List.map (fun c -> f * c)
|> Poly
static member private shift n (Poly cs) =
List.replicate n 0.0 @ cs |> Poly
static member (*) (Poly cs1, p2 : Polynom) : Polynom =
cs1
|> List.mapi (fun i c -> Polynom.shift i (c * p2))
|> List.sum
static member (/) (Poly cs1, f : float) : Polynom =
cs1
|> List.map (fun c -> c / f)
|> Poly
这里我只使用float
列表来表示多项式的系数(所以X^2 + 2X + 3
是Poly [3.0; 2.0; 1.0]
注意i
系数是{ X^i
。
有了这个,我们可以使用几乎与以前相同的功能:
let getPolynom (points : (float * float)[]) =
let indizes = [0..points.Length-1]
let p j =
indizes
|> List.map (fun k ->
if k <> j
then (Polynom.X - Polynom.Const (fst points.[k]))
/ (fst points.[j] - fst points.[k])
else Polynom.One)
|> List.fold (*) Polynom.One
indizes |> List.sumBy (fun j -> Polynom.Const (snd points.[j]) * p j)
正如您所看到的,我使用了相同的函数,并且只用x
替换了参数Polynom.X
并将常量包装为approbiatley。
以下是两个例子(将它们与它们应该正确的Wiki-Page进行比较):
> LagrangeInterpolation.getPolynom
[|(1.0, 1.0); (2.0, 4.0); (3.0, 9.0)|] |> string;;
val it : string = "0.0X^0 + 0.0X^1 + 1.0X^2"
> LagrangeInterpolation.getPolynom
[| 1.0,1.0; 2.0,8.0; 3.0,27.0 |] |> string;;
val it : string = "6.0X^0 + -11.0X^1 + 6.0X^2"
模块内部的完整代码是:
module LagrangeInterpolation =
let private ofLen n cs =
let l = List.length cs
if l < n
then cs @ List.replicate (n-l) 0.0
else cs
type Polynom =
Poly of float list with
override p.ToString () =
match p with
| Poly coefs ->
System.String.Join (" + ", coefs |> List.mapi (fun i c -> sprintf "%AX^%d" c i))
static member Const c = Poly [c]
static member Zero = Polynom.Const 0.0
static member One = Polynom.Const 1.0
static member X = Poly [0.0; 1.0]
static member (+) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a+b)
|> Poly
static member (-) (Poly cs1, Poly cs2) =
let m = max (List.length cs1) (List.length cs2)
List.zip (ofLen m cs1) (ofLen m cs2)
|> List.map (fun (a,b) -> a-b)
|> Poly
static member (*) (f : float, Poly cs2) : Polynom =
cs2
|> List.map (fun c -> f * c)
|> Poly
static member private shift n (Poly cs) =
List.replicate n 0.0 @ cs |> Poly
static member (*) (Poly cs1, p2 : Polynom) : Polynom =
cs1
|> List.mapi (fun i c -> Polynom.shift i (c * p2))
|> List.sum
static member (/) (Poly cs1, f : float) : Polynom =
cs1
|> List.map (fun c -> c / f)
|> Poly
let getPolynom (points : (float * float)[]) =
let indizes = [0..points.Length-1]
let p j =
indizes
|> List.map (fun k ->
if k <> j
then (Polynom.X - Polynom.Const (fst points.[k]))
/ (fst points.[j] - fst points.[k])
else Polynom.One)
|> List.fold (*) Polynom.One
indizes |> List.sumBy (fun j -> Polynom.Const (snd points.[j]) * p j)
为了获得更好的输出,您应该添加一些简化(例如Poly [1.0;0.0] -> Poly [1.0]
)并改进ToString
方法,但我确定您可以处理;)
答案 1 :(得分:1)
如果你的意思是 partial 的函数,即它的某些输入未定义,那么通常有两种方法可以解决这个问题。一种选择是使用option<'T>
类型并在Some
中包装正确的结果,或者在未定义值时返回None
。例如:
let safeDivide a b =
if b = 0 then None else Some(a / b)
调用者不得不对结果进行模式匹配(或者使用类似Maybe computation builder之类的东西),这会使函数调用更加困难,但您可以完全控制错误的处理方式。
另一种选择是抛出异常。对于整数除法,这会自动发生,但您可以这样写:
let safeDivide a b =
if b = 0 then invalidArg "b" "Division by zero!"
a / b
这更容易编写,但您需要了解行为并正确处理异常。