[英]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))
不幸的是,這時我意識到一些函數在庫中被標記為內部函數,因此沒有公開,但是我在這里的一個工作示例中重新創建了它們,以便您可以測試您的函數,該函數與float
和float32
很好地配合使用。
一個新版本將在今年年底之前發布,但是與此同時,您可以對其進行分支,刪除內部內容並進行編譯,或者只是重新創建函數,如在鏈接示例中所做的那樣。
如果您對通用數學感興趣,請隨時為代碼或用例做貢獻。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.