繁体   English   中英

F#通用数学:如何使用op_GreaterThan编写函数

[英]F# Generic Math: how to write function with op_GreaterThan

在F#中,如何编写通用数学步函数?

(Oliver)Heaviside步阶函数是一个函数,如果x为负,则返回零,否则将其微调为1。

这是到目前为止我的尝试的摘要:

// attempt 1:
let inline stepFct1< ^T when ^T : (static member op_GreaterThan: ^T * float -> bool) 
    >     (x:^T) : ^T = 
    //if (^T : (static member op_GreaterThan) (x 0.0) ) then x  //ouch fails also
    if  (>) x 0.0 then x
    else 0.0

编译器说:错误FS0001:类型参数缺少约束^ T:比较时

// attempt 2:
let inline stepFct2<^T when ^T : (static member (>): ^T * ^T -> bool) > (x:^T) : ^T = 
    match x with 
    | x when x > 0.0 -> 1.0
    | 0.0

FSC说:错误FS0010:模式中出现意外的中缀运算符

动机:

我试图在此处重写Ian的Cumulative-Normal和Black-Scholes函数以使用自动微分(DiffSharp)。 Ian的“累积法线”适用于浮点数,我想要适用于任何数字类型(包括AutoDiff.DualG)的通用版本。 累积法线函数包含一个“大于”语句。

编辑:古斯塔沃,谢谢,我已经接受了您的答案-现在可以编译简单的step函数。

但这似乎对累积正常情况没有帮助。 给出以下代码:

// Cumulative Normal Distribution Function - attempt to write a generic version
let inline CDF(x:^T) : ^T = 
    let (b1,b2,b3)  = (0.319381530, -0.356563782, 1.781477937)
    let (b4,b5)     = (-1.821255978, 1.330274429)
    let (p , c )    = (0.2316419  ,  0.39894228)
    let (zero, one) = (LanguagePrimitives.GenericZero, LanguagePrimitives.GenericOne)
    if x > zero then
        let t = one / (one + p * x) 
        (one - c * exp( -x * x / 2.0)* t * (t*(t*(t*(t*b5+b4)+b3)+b2)+b1)) 
    else
        let t = 1.0 / (one - p * x) 
        (c * exp( -x * x / 2.0)* t * (t*(t*(t*(t*b5+b4)+b3)+b2)+b1))

FSI说:

C:\stdin(116,32): warning FS0064: This construct causes code to be less generic 
than indicated by the type annotations. 
The type variable 'T has been constrained to be type 'float'.

val inline CDF : x:float -> float
> CDF 0.1M;;
CDF 0.1M;;
----^^^^
C:\stdin(122,5): error FS0001: This expression was expected to have type
    float
but here has type
    decimal
>

有人知道如何使CDF通用吗?

使用LanguagePrimitives.GenericZero / GenericOne并让类型推断完成其余的工作

// attempt 1:
let inline stepFct1 x =
    let zero = LanguagePrimitives.GenericZero 
    if x > zero then x
    else zero

我看了您发送的链接与要实现的功能。 FSharpPlus(F#+)可以帮助您编写通用数学代码,因为它包含专用的通用编号模块 或者至少您可以从那里掌握一些技术。

UPDATE

关于更新的问题,这将复杂性提高到了一个更高的水平,这是使用最新版本的F#+项目的解决方案:

let inline CDF(x:^T) : ^T = 
    let num x = fromRational (x </ratio/> 1000000000I)
    let (b1,b2,b3)  = (num 319381530I   , num -356563782I  , num 1781477937I)
    let (b4,b5)     = (num -1821255978I , num 1330274429I)
    let (p , c )    = (num  0231641900I , num 0398942280I)
    let (zero, one, two) = 0G, 1G, 2G
    if x > zero then
        let t = one / (one + p * x) 
        (one - c * exp( -x * x / two)* t * (t*(t*(t*(t*b5+b4)+b3)+b2)+b1)) 
    else
        let t = one / (one - p * x) 
        (c * exp( -x * x / two)* t * (t*(t*(t*(t*b5+b4)+b3)+b2)+b1))

不幸的是,这时我意识到一些函数在库中被标记为内部函数,因此没有公开,但是我在这里的一个工作示例中重新创建了它们,以便您可以测试您的函数,该函数与floatfloat32很好地配合使用。

一个新版本将在今年年底之前发布,但是与此同时,您可以对其进行分支,删除内部内容并进行编译,或者只是重新创建函数,如在链接示例中所做的那样。

如果您对通用数学感兴趣,请随时为代码或用例做贡献。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM