scala - 如何找到适合 32 位整数的 n 的最大倍数

标签 scala random functional-programming mod

我正在阅读 Scala 中的函数式编程,但在理解一段代码时遇到了困难。我检查了这本书的勘误表,有问题的段落没有打印错误。 (实际上,它确实有一个打印错误,但打印错误不影响我有疑问的代码。)

有问题的代码计算一个小于某个上限的伪随机非负整数。执行此操作的函数称为 nonNegativeLessThan

trait RNG {
  def nextInt: (Int, RNG) // Should generate a random `Int`. 
}

case class Simple(seed: Long) extends RNG {
  def nextInt: (Int, RNG) = {
    val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL // `&` is bitwise AND. We use the current seed to generate a new seed.
    val nextRNG = Simple(newSeed) // The next state, which is an `RNG` instance created from the new seed.
    val n = (newSeed >>> 16).toInt // `>>>` is right binary shift with zero fill. The value `n` is our new pseudo-random integer.
    (n, nextRNG) // The return value is a tuple containing both a pseudo-random integer and the next `RNG` state.
  }
}

type Rand[+A] = RNG => (A, RNG)

def nonNegativeInt(rng: RNG): (Int, RNG) = {
  val (i, r) = rng.nextInt
  (if (i < 0) -(i + 1) else i, r)
}

def nonNegativeLessThan(n: Int): Rand[Int] = { rng =>
  val (i, rng2) = nonNegativeInt(rng)
  val mod = i % n
  if (i + (n-1) - mod >= 0) (mod, rng2)
  else nonNegativeLessThan(n)(rng2)
}

我无法理解 nonNegativeLessThan 中的以下代码,它看起来像这样:if (i + (n-1) - mod >= 0) (mod, rng2)

这本书解释说,整个 if-else 表达式是必要的,因为简单地采用 nonNegativeInt 结果的模的简单实现会略微偏向较低的值,因为 Int.MaxValue 无法保证是n的倍数。因此,此代码旨在检查 nonNegativeInt 生成的输出是否大于 32 位值中 n 的最大倍数。如果生成的数字大于 32 位值中 n 的最大倍数,该函数将重新计算伪随机数。

详细来说,简单的实现看起来像这样:

def naiveNonNegativeLessThan(n: Int): Rand[Int] = map(nonNegativeInt){_ % n}

其中map定义如下

def map[A,B](s: Rand[A])(f: A => B): Rand[B] = {
  rng => 
    val (a, rng2) = s(rng)
    (f(a), rng2)
}

重复一遍,这种天真的实现是不可取的,因为当 Int.MaxValue 不是 n 的完美倍数时,它会稍微偏向较低的值。

因此,重申一下这个问题:以下代码的作用是什么?它如何帮助我们确定一个数字是否小于 32 位整数中 n 的最大倍数?我在 nonNegativeLessThan 中谈论这段代码:

if (i + (n-1) - mod >= 0) (mod, rng2)
else nonNegativeLessThan(n)(rng2)

最佳答案

我对 Scala 中的函数式编程 中的这段话有完全相同的困惑。我完全同意 jwvh 的分析 - 声明 if (i + (n-1) - mod >= 0) 将永远是 true

关于scala - 如何找到适合 32 位整数的 n 的最大倍数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58635476/

相关文章:

sockets - 如何处理java.net.SocketException : too many open files in dispatch/reboot?

scala - 如何使这段代码更实用

java - 如何在 lift JSON 中序列化和反序列化 Java 8 dateTime?

python - 为什么使用 numpy.random.seed 不是一个好习惯?

php - MySQL ORDER BY rand(),名称为 ASC

C# 随机浮点闭区间

javascript - 为什么 JavaScript 中的不变性如此重要(或需要)?

haskell - 了解函数中的 Haskell 递归

kotlin - 我如何在枚举中使用函数引用?

scala - 如何从子类获取类型参数