当前位置 : 主页 > 网络安全 > 测试自动化 >

性能 – 功能化数字代码

来源:互联网 收集:自由互联 发布时间:2021-06-22
玩F#,我试图以更实用的方式思考代码.我工作的很大一部分恰好是数字化的,所以我在想这种再教育是否有意义.是否正在以一种功能性的方式编写数字代码,例如试图在圆孔中安装方形钉
玩F#,我试图以更实用的方式思考代码.我工作的很大一部分恰好是数字化的,所以我在想这种再教育是否有意义.是否正在以一种功能性的方式编写数字代码,例如试图在圆孔中安装方形钉,或者它只是一个陡峭的学习曲线而不管应用程序如何?

例如,让我们拿一个片段来演示大数的弱定律:

open System
open System.IO
open System.Windows.Forms
open System.Windows.Forms.DataVisualization
open FSharp.Data
open FSharp.Charting
open FSharp.Core.Operators
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.Random
open MathNet.Numerics.Distributions
open MathNet.Numerics.Statistics


let T = 1000

let arr1 = Array.init T (fun i -> float i*0.)
for i in 0 .. T-1 do
    arr1.[i] <- [|for j in 1..i do yield Exponential.Sample(0.1)|] |> Statistics.Mean

let arr2 = Array.init T (fun i -> float i*0.)
for i in 0 .. T-1 do
    arr2.[i] <- arr1.[1 .. i] |> Statistics.Mean

arr2 |> Chart.Line |> Chart.Show

是否有一种简洁的功能性表达方式?有多少功能范例可以融入到这样的工作中?

不确定问题是否属于主题.谢谢.

我首先不要将对Array.init的调用分开并设置初始值.您可以使用@ s952163在其答案中使用的表单,或者根据您的代码:

let arr1 = Array.init T (fun i ->
    [|for j in 1..i do yield Exponential.Sample 0.1 |] |> Statistics.Mean
)

问题是你正在分配中间数组,这是昂贵的 – 而且你无论如何都要在计算平均值之后丢弃它们.替代方案:

let arr1 = Array.init T (fun i ->
    Exponential.Samples 0.1 |> Seq.take (i+1) |> Seq.average
)

现在对于第二部分:您重复计算元素1..i的平均值,这将成为O(n ^ 2)运算.您可以通过使用元素1..i的总和是元素1 .. {i-1}加上第i个元素的总和来在O(n)中求解它.

let sums, _ =
    arr1
    |> Array.mapFold (fun sumSoFar xi ->
        let s = sumSoFar + xi
        s, s
    ) 0.0
let arr2 = 
    sums
    |> Array.mapi (fun i sumi -> sumi / (float (i + 1)))

当然,你们都可以在一个管道中写出来.

或者,使用库函数Array.scan来计算累积总和,在这种情况下,这将给出长度为T 1的结果,然后从中删除第一个元素:

let arr2 =
    Array.sub (Array.scan (+) 0.0 arr1) 1 T
    |> Array.mapi (fun i sumi -> sumi / (float (i + 1)))

或避免中间数组:

Seq.scan (+) 0.0 arr1
|> Seq.skip 1
|> Seq.mapi (fun i sumi -> sumi / (float (i + 1)))
|> Seq.toArray
网友评论