0 <= x < 2^64 之间的 Scalacheck 数字生成器
Scalacheck number generator between 0 <= x < 2^64
我正在尝试在 C 中纠正一个涵盖 uint64_t
的好数字生成器。这是我目前所拥有的。
def uInt64s : Gen[BigInt] = Gen.choose(0,64).map(pow2(_) - 1)
这是一个好的开始,但它只生成数字 2^n - 1
。有没有更有效的方法来生成随机 BigInts,同时保留数字范围 0 <= n < 2^64
?
使用 ScalaCheck...
从 0..Long.MaxValue 生成数字很容易。
从 0..Long.MaxValue..2^64-1 生成一个 unsigned long 不是那么容易。
尝试过:
❌ Gen.chooseNum(BigInt(0),BigInt(2).pow(64)-1)
不起作用: 此时没有为 BigInt 定义隐式。
❌ Arbitrary.arbBigInt.arbitrary
不起作用:它是 BigInt 类型,但仍然限于有符号 Long 的范围。
✔ 生成一个 Long as BigInt 并任意左移以生成 UINT64
有效: 以 Rickard Nilsson 的 ScalaCheck 代码为指南这通过了测试。
这是我想出的:
// 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()
如前所述,,生成的 BigInts 分布不均匀。首选生成器是@stholzm 解决方案:
def genUInt64b : Gen[BigInt] =
Gen.chooseNum(Long.MinValue,Long.MaxValue) map (x =>
BigInt(x) + BigInt(2).pow(63))
它更简单,输入到 ScalaCheck 的数字分布更均匀,速度更快,并且通过了测试。
的更简单、更有效的替代方法如下:
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)
这是我目前的情况,我不是很满意
/**
* 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
的数字
如果您看到可以改进的地方或修复的错误,请免费发表评论
好吧,也许我在这里遗漏了一些东西,但这不是这么简单吗?
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
做加法当然可以。
我很好奇生成值的分布。显然 chooseNum
的分布不均匀,因为它更喜欢特殊值,但 Longs 的边缘情况可能对 UInt64s 也很有趣:
/** 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*)(
我正在尝试在 C 中纠正一个涵盖 uint64_t
的好数字生成器。这是我目前所拥有的。
def uInt64s : Gen[BigInt] = Gen.choose(0,64).map(pow2(_) - 1)
这是一个好的开始,但它只生成数字 2^n - 1
。有没有更有效的方法来生成随机 BigInts,同时保留数字范围 0 <= n < 2^64
?
使用 ScalaCheck...
从 0..Long.MaxValue 生成数字很容易。
从 0..Long.MaxValue..2^64-1 生成一个 unsigned long 不是那么容易。
尝试过:
❌ Gen.chooseNum(BigInt(0),BigInt(2).pow(64)-1)
不起作用: 此时没有为 BigInt 定义隐式。
❌ Arbitrary.arbBigInt.arbitrary
不起作用:它是 BigInt 类型,但仍然限于有符号 Long 的范围。
✔ 生成一个 Long as BigInt 并任意左移以生成 UINT64
有效: 以 Rickard Nilsson 的 ScalaCheck 代码为指南这通过了测试。
这是我想出的:
// 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()
如前所述,
def genUInt64b : Gen[BigInt] =
Gen.chooseNum(Long.MinValue,Long.MaxValue) map (x =>
BigInt(x) + BigInt(2).pow(63))
它更简单,输入到 ScalaCheck 的数字分布更均匀,速度更快,并且通过了测试。
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)
这是我目前的情况,我不是很满意
/**
* 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
如果您看到可以改进的地方或修复的错误,请免费发表评论
好吧,也许我在这里遗漏了一些东西,但这不是这么简单吗?
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
做加法当然可以。
我很好奇生成值的分布。显然 chooseNum
的分布不均匀,因为它更喜欢特殊值,但 Longs 的边缘情况可能对 UInt64s 也很有趣:
/** 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*)(