【问题标题】:How to find the largest multiple of n that fits in a 32 bit integer如何找到适合 32 位整数的 n 的最大倍数
【发布时间】:2020-02-26 08:22:15
【问题描述】:

我正在阅读 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 &gt;= 0) (mod, rng2)

这本书解释说,整个 if-else 表达式是必要的,因为简单地采用 nonNegativeInt 的结果的 mod 的简单实现会稍微偏向较低的值,因为 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)

【问题讨论】:

  • 据我所知,它没有做任何事情,因为条件永远不会 false。由于i 保证为非负数,而n 假定 为正数,这将mod 置于零到n-1 的范围内,包括0 到n-1。所以(n-1) - mod 也是非负数。因此if 条件始终为true

标签: scala random functional-programming mod


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    事实上,如果在 Rust 中尝试相同的示例,编译器会对此发出警告(只是一个有趣的比较正在执行多少静态检查)。当然,jwvh 的纸笔方法绝对是正确的方法。

    我们首先定义了一些类型别名,以使代码更接近 Scala 代码(请原谅我的 Rust,如果它不是很惯用的话)。

    pub type RNGType = Box<dyn RNG>;
    pub type Rand<A> = Box<dyn Fn(RNGType) -> (A, RNGType)>;
    
    pub fn non_negative_less_than_(n: u32) -> Rand<u32> {
        let t = move |rng: RNGType| {
            let (i, rng2) = non_negative_int(rng);
            let rem = i % n;
            if i + (n - 1) - rem >= 0 {
                (rem, rng2)
            } else {
                non_negative_less_than(n)(rng2)
            }
        };
    
        Box::new(t)
    }
    

    关于if nn + (n - 1) - rem &gt;= 0 的编译器警告是:

    warning: comparison is useless due to type limits
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-22
      • 2013-04-28
      • 1970-01-01
      • 2022-11-17
      • 1970-01-01
      • 2011-06-10
      • 1970-01-01
      相关资源
      最近更新 更多