初始化无限的BigIntegers列表

时间:2011-06-09 06:11:00

标签: f# ienumerable sequence biginteger seq

确定, 所以我需要一个所有正整数的列表。 首先想到的是:

let numbers:Seq<bigint>=Seq.initInfinite n...

但initInfite实际上并不是infitint:http://msdn.microsoft.com/en-us/library/ee370429.aspx (与bigint不同)它唯一:Int32.MaxValue = 2,147,483,647,这远远不够大。

目前我的计划是用某种手工制作的类替换序列(可能会暗示IEnumerable)。它会很简单(可能对我的使用更有效)但我想知道如何做到这一点

4 个答案:

答案 0 :(得分:12)

Seq.unfold (fun n -> Some(n, n + 1I)) 0I

答案 1 :(得分:5)

let numbers:bigint seq = 
    let rec loop n = seq { yield n; yield! loop (n+1I) }
    loop 0I

答案 2 :(得分:3)

我保持以下静态约束函数,因为它非常灵活(您可以指定起始值和跳过间隔)并适用于所有数字类型:

let inline infiniteRange start skip = 
    seq {
        let n = ref start
        while true do
            yield n.contents
            n.contents <- n.contents + skip
    }

FSI提供的类型签名:

val inline infiniteRange :
   ^a ->  ^b -> seq< ^a>
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^a)

以下是生成所有整数的方法(BigInts,即 - 在FSI中显示):

> infiniteRange 1I 1I;;
val it : seq<System.Numerics.BigInteger> =
  seq [1 {IsEven = false;
          IsOne = true;
          IsPowerOfTwo = true;
          IsZero = false;
          Sign = 1;}; 2 {IsEven = true;
                         IsOne = false;
                         IsPowerOfTwo = true;
                         IsZero = false;
                         Sign = 1;}; 3 {IsEven = false;
                                        IsOne = false;
                                        IsPowerOfTwo = false;
                                        IsZero = false;
                                        Sign = 1;}; 4 {IsEven = true;
                                                       IsOne = false;
                                                       IsPowerOfTwo = true;
                                                       IsZero = false;
                                                       Sign = 1;}; ...]

更新,正如Daniel所示,您可以使用通用语言基元轻松地编写另一个静态约束函数infiniteRange,内置跳过1:

let inline infiniteRangeSkip1 start = 
    infiniteRange start LanguagePrimitives.GenericOne

这是类型签名:

val inline infiniteRangeSkip1 :
   ^a -> seq< ^a>
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^a) and
          ^b : (static member get_One : ->  ^b)

答案 3 :(得分:2)

如果这是您经常需要的话,您甚至可以考虑扩展Seq模块。

module Seq =
  let initInfiniteBig = 
    seq {
      let i = ref 0I
      while true do 
        yield !i
        i := !i + 1I
    }

let ten = Seq.initInfiniteBig |> Seq.take 10

更新

我对一些变化进行了基准测试:

let initInfiniteBig = 
  seq {
    let i = ref 0I
    while true do 
      yield !i
      i := !i + 1I
  }

let initInfiniteBig2 = 
  seq {
    let i = ref 0I
    while true do 
      yield i.contents
      i.contents <- i.contents + 1I
  }

let initInfiniteBig3 = 
  let rec loop i = 
    seq {
      yield i
      yield! loop (i + 1I)
    }
  loop 0I

let initInfiniteBig4 = Seq.unfold (fun n -> Some(n, n + 1I)) 0I

let range s = s |> Seq.take 100000000 |> Seq.length |> ignore

range initInfiniteBig  //Real: 00:00:29.913, CPU: 00:00:29.905, GC gen0: 0, gen1: 0, gen2: 0
range initInfiniteBig2 //Real: 00:00:30.045, CPU: 00:00:30.045, GC gen0: 0, gen1: 0, gen2: 0
range initInfiniteBig3 //Real: 00:00:40.345, CPU: 00:00:40.310, GC gen0: 2289, gen1: 5, gen2: 0
range initInfiniteBig4 //Real: 00:00:30.731, CPU: 00:00:30.716, GC gen0: 1146, gen1: 4, gen2: 1

更新2

这是一个通用范围函数,如Stephen's,但没有startskip

let inline infiniteRange() : seq<'a> = 
  let zero : 'a = LanguagePrimitives.GenericZero
  let one : 'a = LanguagePrimitives.GenericOne
  seq {
      let n = ref zero
      while true do
          yield !n
          n := !n + one
  }

这是签名:

unit -> seq< ^a>
    when  ^a : (static member get_Zero : ->  ^a) and
          ^a : (static member get_One : ->  ^a) and
          ^a : (static member ( + ) :  ^a *  ^a ->  ^a)

基准:

range (infiniteRange() : seq<bigint>) //Real: 00:00:30.042, CPU: 00:00:29.952, GC gen0: 0, gen1: 0, gen2: 0