我试图纠正一个涵盖C中uint64_t
的数字生成器。这是我到目前为止所做的。
def uInt64s : Gen[BigInt] = Gen.choose(0,64).map(pow2(_) - 1)
这是一个好的开始,但它只生成数字2^n - 1
。在保留数字范围0 <= n < 2^64
的同时,是否有更有效的方法来生成随机BigInts?
答案 0 :(得分:4)
好吧,也许我在这里遗漏了一些东西,但这不是很简单吗?
def uInt64s : Gen[BigInt] = Gen.chooseNum(Long.MinValue,Long.MaxValue)
.map(x => BigInt(x) + BigInt(2).pow(63))
Longs已经拥有正确的位数 - 只需添加2 ^ 63,Long.MinValue
变为0,Long.MaxValue
变为2 ^ 64 - 1.并添加BigInt
s当然。
我对生成的值的分布感到好奇。显然chooseNum
的分布并不统一,因为它更喜欢特殊值,但Longs的边缘情况对于UInt64来说可能也很有趣:
/** Generates numbers within the given inclusive range, with
* extra weight on zero, +/- unity, both extremities, and any special
* numbers provided. The special numbers must lie within the given range,
* otherwise they won't be included. */
def chooseNum[T](minT: T, maxT: T, specials: T*)(
答案 1 :(得分:1)
With ScalaCheck...
Generating a number from 0..Long.MaxValue is easy.
Generating an unsigned long from 0..Long.MaxValue..2^64-1 is not so easy.
Tried:
❌ Gen.chooseNum(BigInt(0),BigInt(2).pow(64)-1)
Does not work: At this time there is not an implicit defined for BigInt.
❌ Arbitrary.arbBigInt.arbitrary
Does not work: It's type BigInt but still limited to the range of signed Long.
✔ Generate a Long as BigInt and shift left arbitrarily to make an UINT64
Works: Taking Rickard Nilsson's, ScalaCheck code as a guide this passed the test.
This is what I came up with:
// Generate a long and map to type BigInt
def genBigInt : Gen[BigInt] = Gen.chooseNum(0,Long.MaxValue) map (x => BigInt(x))
// Take genBigInt and shift-left a chooseNum(0,64) of positions
def genUInt64 : Gen[BigInt] = for { bi <- genBigInt; n <- Gen.chooseNum(0,64); x = (bi << n) if x >= 0 && x < BigInt(2).pow(64) } yield x
...
// Use the generator, genUInt64()
As noted, Scalacheck number generator between 0 <= x < 2^64, the distribution of the BigInts generated is not even. The preferred generator is @stholzm solution:
def genUInt64b : Gen[BigInt] =
Gen.chooseNum(Long.MinValue,Long.MaxValue) map (x =>
BigInt(x) + BigInt(2).pow(63))
it is simpler, the numbers fed to ScalaCheck will be more evenly distributed, it is faster, and it passes the tests.
答案 2 :(得分:1)
stholmz's answer的更简单,更有效的替代方法如下:
val myGen = {
val offset = -BigInt(Long.MinValue)
Arbitrary.arbitrary[Long].map { BigInt(_) + offset }
}
Long
; BigInt
; -BigInt(Long.MinValue)
)。REPL中的测试:
scala> myGen.sample
res0: Option[scala.math.BigInt] = Some(9223372036854775807)
scala> myGen.sample
res1: Option[scala.math.BigInt] = Some(12628207908230674671)
scala> myGen.sample
res2: Option[scala.math.BigInt] = Some(845964316914833060)
scala> myGen.sample
res3: Option[scala.math.BigInt] = Some(15120039215775627454)
scala> myGen.sample
res4: Option[scala.math.BigInt] = Some(0)
scala> myGen.sample
res5: Option[scala.math.BigInt] = Some(13652951502631572419)
答案 3 :(得分:0)
这是我到目前为止所做的,我对此并不满意
/**
* Chooses a BigInt in the ranges of 0 <= bigInt < 2^^64
* @return
*/
def bigInts : Gen[BigInt] = for {
bigInt <- Arbitrary.arbBigInt.arbitrary
exponent <- Gen.choose(1,2)
} yield bigInt.pow(exponent)
def positiveBigInts : Gen[BigInt] = bigInts.filter(_ >= 0)
def bigIntsUInt64Range : Gen[BigInt] = positiveBigInts.filter(_ < (BigInt(1) << 64))
/**
* Generates a number in the range 0 <= x < 2^^64
* then wraps it in a UInt64
* @return
*/
def uInt64s : Gen[UInt64] = for {
bigInt <- bigIntsUInt64Range
} yield UInt64(bigInt)
由于Arbitrary.argBigInt.arbitrary
似乎只有-2^63 <= x <= 2^63
范围,因此我有时会使用x^2
来获得大于2^63
的数字
如果您发现可以进行地方改进或修复错误,可以免费评论