Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在F中重写C#代码# 只是和F和拉格朗日纠缠在一起,试图创建一个基于C版本(从C++ wiki条目复制)的基本的拉格朗日插值函数:_C#_F#_Rewrite_Functional Programming - Fatal编程技术网

在F中重写C#代码# 只是和F和拉格朗日纠缠在一起,试图创建一个基于C版本(从C++ wiki条目复制)的基本的拉格朗日插值函数:

在F中重写C#代码# 只是和F和拉格朗日纠缠在一起,试图创建一个基于C版本(从C++ wiki条目复制)的基本的拉格朗日插值函数:,c#,f#,rewrite,functional-programming,C#,F#,Rewrite,Functional Programming,有人能基于相同的C代码提供更好/更整洁的F版本吗 就个人而言,我认为简单的if/elif/else结构在这里看起来更好,而不会产生诸如 match i with |i when i=... 这是一个非递归的解决方案。这有点奇怪,因为该算法需要索引,但希望它能显示F#的函数是如何组成的: let Lagrange (pos : float[]) (vals : float[]) desiredPos = let weight pos desiredPos (i,v) =

有人能基于相同的C代码提供更好/更整洁的F版本吗

就个人而言,我认为简单的if/elif/else结构在这里看起来更好,而不会产生诸如

match i with   
|i when i=...

这是一个非递归的解决方案。这有点奇怪,因为该算法需要索引,但希望它能显示F#的函数是如何组成的:

let Lagrange (pos : float[]) (vals : float[]) desiredPos = 
    let weight pos desiredPos (i,v) =
        let w = pos |> Array.mapi (fun j p -> j,p)
                    |> Array.filter (fun (j,p) -> i <> j)
                    |> Array.fold (fun acc (j,p) -> acc * (desiredPos - p)/(pos.[i] - p)) 1.
        w * v
    vals |> Array.mapi (fun i v -> i,v)
         |> Array.sumBy (weight pos desiredPos)
让拉格朗日(pos:float[])(vals:float[])期望pos=
让重量pos期望pos(i,v)=
设w=pos |>Array.mapi(fun j p->j,p)
|>Array.filter(fun(j,p)->ij)
|>Array.fold(fun acc(j,p)->acc*(desiredPos-p)/(pos[i]-p))1。
w*v
vals |>Array.mapi(乐趣i v->i,v)
|>Array.sumBy(所需重量位置)

我认为这可以作为命令式代码使用:

let LagrangeI(pos:_[], v:_[], desiredPos) =
    let mutable retVal = 0.0
    for i in 0..v.Length-1 do
        let mutable weight = 1.0
        for j in 0..pos.Length-1 do
            // The i-th term has to be skipped
            if j <> i then
                weight <- weight * (desiredPos - pos.[j]) / (pos.[i] - pos.[j])
        retVal <- retVal + weight * v.[i]
    retVal

折叠序列是用累加器替换循环的常用方法

let Lagrange(pos:_[], v:_[], desiredPos) =
  seq {0 .. v.Length-1} 
  |> Seq.fold (fun retVal i -> 
      seq {for j in 0 .. pos.Length-1 do if i <> j then yield j} 
      |> Seq.fold (fun w j -> w * (desiredPos - pos.[j]) / (pos.[i] - pos.[j])) 1.0
      |> (fun weight -> weight * v.[i] + retVal)) 0.0
let Lagrange(pos:[],v:[],desiredPos)=
seq{0..v.Length-1}
|>顺序折叠(趣味检索i->
seq{对于0..pos.Length-1中的j,如果i j,则产生j}
|>顺序(fun w j->w*(所需位置-位置[j])/(位置[i]-位置[j])1.0
|>(有趣的重量->重量*v[i]+retVal))0.0

使功能解决方案难看的部分是跳过第i个元素,这意味着索引。将其拉入一个可重用函数中,以便隔离所有丑陋的索引处理。我叫我的循环赛

let RoundRobin l = seq {
  for i in {0..Seq.length l - 1} do
    yield (Seq.nth i l, Seq.take i l |> Seq.append <| Seq.skip (i+1) l)
}
现在生成代码相当简单:

let Lagrange pos value desiredPos = Seq.sum (seq {
  for (v,(p,rest)) in Seq.zip value (RoundRobin pos) do
    yield v * prod (seq { for p' in rest do yield (desiredPos - p') / (p - p') })
})
RoundRobin确保pos[i]不包含在内部循环中的其他pos中。为了包含
val
数组,我用圆形的robinned
pos
数组将其压缩

这里的教训是,在功能性风格中,索引非常难看。
我还发现了一个很酷的技巧:
|>Seq.append如果你只是在胡闹,那么这里有一个类似于Brian的版本,它使用函数currying和元组管道操作符

let Lagrange(pos:_[], v:_[], desiredPos) =
    let foldi f state = Seq.mapi (fun i x -> i, x) >> Seq.fold f state
    (0.0, v) ||> foldi (fun retVal (i, posi) -> 
        (1.0, pos) ||> foldi (fun weight (j, posj) -> 
            if j <> i then
                (desiredPos - posj) / (posi - posj)
            else
                1.0)
        |> (fun weight -> weight * posi + retVal))
let Lagrange(pos:[],v:[],desiredPos)=
让foldi f state=Seq.mapi(fun i x->i,x)>>Seq.fold f state
(0.0,v)| |>foldi(funretval(i,posi)->
(1.0,pos)| |>foldi(趣味重量(j,posj)->
如果j i那么
(desiredPos-posj)/(posi-posj)
其他的
1.0)
|>(趣味重量->重量*posi+retVal))
我的尝试:

let Lagrange(p:_[], v, desiredPos) =
    let Seq_multiply = Seq.fold (*) 1.0
    let distance i j = if (i=j) then 1.0 else (desiredPos-p.[j])/(p.[i]-p.[j])
    let weight i = p |> Seq.mapi (fun j _ -> distance i j) |> Seq_multiply
    v |> Seq.mapi (fun i vi -> (weight i)*vi) |> Seq.sum
通过使内部循环成为函数来重构。此外,我们还可以通过定义一些有意义的函数使代码更加直观和“易懂”

此外,此重写突出显示了原始代码(以及所有其他变体)中的错误。距离函数实际上应该是:

let distance i j = if (p.[i]=p.[j]) then 1.0 else (desiredPos-p.[j])/(p.[i]-p.[j])
避免了一般的div为零的错误。这就产生了一种通用的无索引解决方案:

let Lagrange(p, v, desiredPos) =
    let distance pi pj = if (pi=pj) then 1.0 else (desiredPos-pj)/(pi-pj)
    let weight pi vi = p |> Seq.map (distance pi) |> Seq.fold (*) vi
    Seq.map2 weight p v |> Seq.sum

我认为这是一个很好的例子,说明命令式代码比函数式代码更易于阅读和维护。您还可以通过将折叠累加器设置为包含索引的元组来取消mapi。v |>fold(fun(retVal,i)posi->newRetValuefunction,i+1)(0.0,0)这确实为我的数据生成了与原始C代码相同的答案
let prod (l : seq<float>) = Seq.reduce (*) l
let Lagrange pos value desiredPos = Seq.sum (seq {
  for (v,(p,rest)) in Seq.zip value (RoundRobin pos) do
    yield v * prod (seq { for p' in rest do yield (desiredPos - p') / (p - p') })
})
let Lagrange(pos:_[], v:_[], desiredPos) =
    let foldi f state = Seq.mapi (fun i x -> i, x) >> Seq.fold f state
    (0.0, v) ||> foldi (fun retVal (i, posi) -> 
        (1.0, pos) ||> foldi (fun weight (j, posj) -> 
            if j <> i then
                (desiredPos - posj) / (posi - posj)
            else
                1.0)
        |> (fun weight -> weight * posi + retVal))
let Lagrange(p:_[], v, desiredPos) =
    let Seq_multiply = Seq.fold (*) 1.0
    let distance i j = if (i=j) then 1.0 else (desiredPos-p.[j])/(p.[i]-p.[j])
    let weight i = p |> Seq.mapi (fun j _ -> distance i j) |> Seq_multiply
    v |> Seq.mapi (fun i vi -> (weight i)*vi) |> Seq.sum
let distance i j = if (p.[i]=p.[j]) then 1.0 else (desiredPos-p.[j])/(p.[i]-p.[j])
let Lagrange(p, v, desiredPos) =
    let distance pi pj = if (pi=pj) then 1.0 else (desiredPos-pj)/(pi-pj)
    let weight pi vi = p |> Seq.map (distance pi) |> Seq.fold (*) vi
    Seq.map2 weight p v |> Seq.sum