F#泛型数学:如何用op_GreaterThan编写函数 [英] F# Generic Math: how to write function with op_GreaterThan
问题描述
一个(Oliver)Heaviside步骤函数是一个函数,如果x是负数,它将返回零,否则它会回退一个。
//尝试1:
let inline stepFct1< ^ T当^ T时:(静态成员op_GreaterThan:^ T * float - > bool)
> (x:^ T):^ T =
// if(^ T:(static member op_GreaterThan)(x 0.0))那么x // ouch也会失败
if(>)x 0.0 then x
else 0.0
编译器说:错误FS0001:类型参数缺少约束'当^ T:comparison'
//尝试2:
let inline stepFct2 <^ T when ^ T :(静态成员(>):^ T * ^ T - > bool)> (x:^ T):^ T =
匹配x和
| x当x> 0.0 - > 1.0
| 0.0
FSC表示:错误FS0010:模式中的意外中缀运算符
动机:
我试图重写Ian的Cumulative-Normal和Black-Scholes函数这里使用自动微分(DiffSharp)。 Ian的Cumulative Normal在浮点工程中工作,我想要一个适用于任何数字类型(包括AutoDiff.DualG)的通用版本。
累积正常函数包含一个大于语句。
编辑:Gustavo,谢谢,我接受了你的答案 - 简单的步骤函数现在编译。
但它似乎没有帮助累积正常情况。
给出以下代码:
//累积正态分布函数 - 试图编写一个通用版本
let (b4,b5)=( - 1.821255978,1.330274429)(b1,b2,b3)=(0.319381530,-0.356563782,1.781477937)
let(b4,b5)
let(p,c)=(0.2316419,0.39894228)
let(zero,one)=(LanguagePrimitives.GenericZero,LanguagePrimitives.GenericOne)
if x>零然后
让t = 1 /(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):警告FS0064 :这个构造使得代码比通过类型注释指示的通用
更少。
类型变量'T'被限制为'float'类型。
val inline CDF:x:float - >浮动
> CDF 0.1M ;;
CDF 0.1M ;;
---- ^^^^
C:\ stdin(122,5):错误FS0001:此表达式预计有类型
float
,但这里有类型
十进制
>
有谁知道如何让CDF变得一般?
GenericOne
其余 //尝试1:
let inline stepFct1 x =
let zero = LanguagePrimitives.GenericZero
如果x>零然后x
else零
我看了一下你用函数发送的链接你想实现。 FSharpPlus(F#+)可以帮助您编写通用的数学代码,因为它包含专用的通用数字模块。或者至少你可以从那里获得一些技巧。
更新
您的更新问题将复杂度提高到更高的水平,这里使用最新版本的 F#+ project:
$ b $ pre $ let inline CDF(x:^ T):^ T =
let num x = (b 1,b 2,b 3)=(数字319381530I,数字-356563782I,数字1781477937I)
let(b4,b5)=(数字 - >数字> 1000000000I) (p,c)=(num 0231641900I,num 0398942280I)
let(zero,one,two)= 0G,1G,2G
if x>零然后
让t = 1 /(one + p * x)
(one-c * exp(-x * x / 2)* t *(t *(t *(t *(t * b5 + b4)+ b3)+ b2)+ b1))
else
let t = one /(one-p * x)
(c * exp(-x * x /两个)* t *(t *(t *(t *(t * b5 + b4)+ b3)+ b2)+ b1))
不幸的是,在这个时候,我意识到一些函数在库中被标记为内部函数,因此没有公开,但我在一个工作示例中重新创建了它们 here ,这样你就可以测试你的函数了,它很适合 float
和 FLOAT32
。 b
$ b
新版本将在今年年底之前发布,但同时你可以分支它,删除内部并编译它,或者重新创建函数就像我在链接的例子中所做的那样。
如果你对Generic Maths感兴趣,可以随意使用代码或用例。
in F#, how does one write a generic-math step function?
An (Oliver) Heaviside step function is function that returns zero if x is negative, otherwise it retuns one.
Here is a summary of my attempts so far:
// 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
compiler says: error FS0001: A type parameter is missing a constraint 'when ^T : comparison'
// 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 says: error FS0010: Unexpected infix operator in pattern
Motivation:
I am trying to rewrite Ian's Cumulative-Normal and Black-Scholes functions here to use Automatic Differentiation (DiffSharp). Ian's Cumulative Normal works on floats, I would like a generic version that works on any numeric type, including AutoDiff.DualG. The cumulative normal function contains a "greater than" statement.
EDIT: Gustavo, thanks, I have accepted your answer - the simple step function now compiles.
But it doesn't seem to help with the Cumulative Normal case. Given this code:
// 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 says:
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
>
Does anyone know how to make CDF generic?
Use LanguagePrimitives.GenericZero
/ GenericOne
and let type inference do the rest
// attempt 1:
let inline stepFct1 x =
let zero = LanguagePrimitives.GenericZero
if x > zero then x
else zero
I had a look at the link you sent with the function you want to implement. FSharpPlus (F#+) may help you to write generic math code since it contains a dedicated Generic Numbers module. Or at least you can grab some techniques from there.
UPDATE
Regarding your updated question, which takes the complexity to a higher level, here is a solution using the latest version of the F#+ project:
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))
Unfortunately at this time I realised some functions were marked as internal in the library and therefore were not exposed, but I re-created them in a working example here so you can test your function, which works nicely with float
and float32
.
A new version will be released before end of this year, but in the mean time you can branch it, remove the internals and compile it, or just re-create the functions as I did in the linked example.
If you are interested in Generic Maths feel free to contribute with code or use cases.
这篇关于F#泛型数学:如何用op_GreaterThan编写函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!