是否有通用的MultiplyByInt?

时间:2012-03-02 03:04:17

标签: f# generic-programming

有一个泛型函数LanguagePrimitives.DivideByInt除以int而不会丢失泛型行为,我们可以像这样使用它:

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;

P.S。我们总是可以使用一些非标准的方法,如:

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

但我很感兴趣是否有可能以正确的方式进行。

4 个答案:

答案 0 :(得分: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

但是你必须指定每种类型。 我宁愿使用这个功能:

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)

我看不出两种方法之间在性能上有任何差异。

答案 1 :(得分: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

将永远循环

答案 2 :(得分: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)

答案 3 :(得分:1)

我收到Don Syme的回复(通过fsbugs电子邮件),当我询问失踪MutliplyByInt并且对DivideByInt的支持有限时:

  唐的答案是:

     

此运算符用于支持“Seq.averageBy”等。这表示总计的伪精确除法。我们没有将机制扩展到超出需要的范围。

所以看起来我误解了这种机制的目的。