2012-03-02 22 views
2

有一個通用的功能LanguagePrimitives.DivideByInt通過int不失一般性的行爲來劃分,我們可以用這樣的:是否有通用的MultiplyByInt?

let inline Divideby2 n = LanguagePrimitives.DivideByInt n 2 

val inline Divideby2 : 
    ^a -> ^a when ^a : (static member DivideByInt : ^a * int -> ^a) 

但是沒有叫MultiplyByInt通過int執行通用乘法函數。有什麼可以執行泛型乘法嗎?就像這樣:

let inline MultiplyBy2 n = SomeGenericFunctionsModule.MultiplybyInt n 2; 

附:我們總是可以使用一些不規範的做法,如:

let inline MultiplyByInt n m = seq { for i in 1..m -> n} |> Seq.sum 

,但我很感興趣,如果有可能以正確的方式去做。

+0

該庫爲'DivideByInt'函數作弊,並使用未記錄的表達式,如果您嘗試使用它們,將會產生警告。提出一個比你的建議更聰明的解決方案是棘手的。 – 2012-03-02 03:56:02

+0

@Dmitry你有沒有試過我的答案?它不需要迭代,所以它肯定會快得多。 – Gustavo 2012-03-08 06:48:37

+0

是的,它工作,謝謝!但是我已經決定這個操作(乘以int)是奇怪的,這不是自然的,而是由設計引起的混亂。實際上,我試圖得到的是當我們只有'GenericOne'和'GenericZero'時獲得一些泛型類型的常量。所以我一直對int不是乘以某些東西感興趣,而是通過用int值乘以'LanguagePrimitives.GenericOne'獲得泛型類型的常量。 – 2012-03-08 09:28:16

回答

5

恐怕沒有內置的功能,但我提出了兩個替代解決方案:

type MulExtension = MulExtension of int with 
    static member (=>) (x:float , MulExtension y) = x * (float y) 
    static member (=>) (x:decimal, MulExtension y) = x * (decimal y) 
    static member (=>) (x:int64 , MulExtension y) = x * (int64 y) 
    // More overloads 

let inline MultiplyByInt x y = x => MulExtension y 

但是,您必須pecify每種類型。 我寧願使用此功能:

let inline MultiplyByInt x y = 
    let fromInt (n:int) : ^a when ^a : (static member (*) : ^a * ^a -> ^a) = 
     System.Convert.ChangeType(n, typeof<'a>) :?> 'a 
    x * (fromInt y) 

我看不到在這兩種方法之間的性能有什麼不同。

2

我設法在O(log(N))一個解決方案,它擊敗你,但仍覺得很醜陋

let inline MulInt (m:^t) (n:int) = 
    let r : ^t ref = ref LanguagePrimitives.GenericZero 
    let addv : ^t ref= ref LanguagePrimitives.GenericOne 
    while ((int) !r) < n do 
     if int(!r + !addv + !addv) < n then 
      addv := !addv + !addv 
     else 
      r := !r + !addv 
      addv := LanguagePrimitives.GenericOne 

    !r * m 

使用一些僅有庫的功能,可以更好地這一點,但會導致警告。

注意:此方法假定n^t表示的 - 即

MulInt 2uy 5000 

將永遠循環下去

1
let inline MultiplyByInt n (x: ^a) = 
    let zero : ^a = LanguagePrimitives.GenericZero 
    let one : ^a = LanguagePrimitives.GenericOne 
    if n = 0 then zero 
    else 
    let mutable q, r = System.Math.DivRem(abs n, 2) 
    let mutable y = x 
    while q > 0 do 
     y <- y + y 
     q <- q/2 
    let y = if r = 0 then y else y + x 
    if n > 0 then y 
    else y * (zero - one) 
+0

不完全正確 - 'MultiplyByInt 3 3 ;; val it:int = 6' - 我認爲當你做'q < - q/2'時你會丟失信息。「 – 2012-03-02 05:22:51

+0

謝謝。它是固定的,雖然還不夠優雅。 – Daniel 2012-03-02 05:26:11

1

我(通過電子郵件fsbugs)收到答覆距離Don賽姆當我問起失蹤MutliplyByInt和有限支持的DivideByInt

唐的回答是:

該運營商的存在是爲了支持「Seq.averageBy」等。這表示總數的計數精確劃分。我們沒有將該機制擴展到超出所需的範圍之外。

所以看起來我誤解了這個機制的目的。