【问题标题】:How can I unify these two float functions?如何统一这两个浮点函数?
【发布时间】:2016-06-16 23:30:25
【问题描述】:

我发现这个neat trick 可以一次性计算数据的平均值和标准差。我想让这个为float32float 工作。 Again,我正在努力用通用数字来解决这个问题。

module Seq =
    let inline private avgVarianceReducer toFloat (count, oldM, oldS) x =
        if count = 1 then
            2, x, LanguagePrimitives.GenericZero
        else
            let meanFree = x - oldM
            let newM = oldM + meanFree / (toFloat count)
            count + 1, newM, oldS + meanFree * (x - newM)

    let inline private avgVarianceWith toFloat source =
        match source |> Seq.fold (avgVarianceReducer toFloat) (1, LanguagePrimitives.GenericZero, LanguagePrimitives.GenericZero) with
        | 0, _, _ -> LanguagePrimitives.GenericZero, LanguagePrimitives.GenericZero
        | 1, mean, _ -> mean, LanguagePrimitives.GenericZero
        | n, mean, var -> mean, var / (n - 2 |> toFloat)

    let avgVariance source = source |> avgVarianceWith float
    let avgVariancef source = source |> avgVarianceWith float32

这两种类型都适用,但我有额外的avgVariancef,而且我必须在调用时选择正确的。

对我来说,核心问题是在avgVarianceReducer 中转换为正确的浮点数,我通过传入正确的转换函数解决了这个问题。我尝试了op_Explicit,但失败了。

有人想出更优雅的解决方案吗?

【问题讨论】:

    标签: generics f# numbers type-conversion type-inference


    【解决方案1】:

    你试过FSharpPlus吗? 它包含一个用于通用数学的模块和您正在寻找的通用 explicit 函数。

    您的代码如下所示:

    #r @"FsControl.dll"
    #r @"FSharpPlus.dll"
    
    open FSharpPlus
    open FSharpPlus.Operators.GenericMath
    
    module Seq =
        let inline private avgVarianceReducer (count, oldM, oldS) (x:'R) =
            if count = 1 then
                2, x, 0G
            else
                let meanFree = x - oldM
                let newM = oldM + meanFree / explicit count
                count + 1, newM, oldS + meanFree * (x - newM)
    
        let inline avgVariance source : 'R * 'R =
            match source |> Seq.fold avgVarianceReducer (1, 0G, 0G) with
            | 0, _, _ -> 0G, 0G
            | 1, mean, _ -> mean, 0G
            | n, mean, var -> mean, var / (n - 2 |> explicit)
    
        // or if you prefer specific functions
        let avgVarianceF32 source : float32 * float32 = avgVariance source
        let avgVarianceF   source : float   * float   = avgVariance source
    
        // it will work with other types as well
        let avgVarianceD source : decimal * decimal   = avgVariance source
    

    实际上你不需要函数explicit,你可以使用函数fromIntegral来代替,它对数字更具体。

    您还可以浏览该库的源代码,只提取您特定案例所需的代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-20
      • 2014-08-23
      相关资源
      最近更新 更多