CoffeeScript 生成可預(yù)測的隨機(jī)數(shù)

2022-06-29 17:04 更新

生成可預(yù)測的隨機(jī)數(shù)

問題

你需要生成在一定范圍內(nèi)的隨機(jī)數(shù),但你也需要對發(fā)生器進(jìn)行“生成種子”操作來提供可預(yù)測的值。

解決方案

編寫你自己的隨機(jī)數(shù)生成器。當(dāng)然有很多方法可以做到這一點(diǎn),這里給出一個簡單的示例。 該發(fā)生器絕對不可以以加密為目的!

class Rand
  # 如果沒有種子創(chuàng)建,使用當(dāng)前時間作為種子
  constructor: (@seed) ->
    # Knuth and Lewis' improvements to Park and Miller's LCPRNG
    @multiplier = 1664525
    @modulo = 4294967296 # 2**32-1;
    @offset = 1013904223
    unless @seed? && 0 <= seed < @modulo
      @seed = (new Date().valueOf() * new Date().getMilliseconds()) % @modulo

  # 設(shè)置新的種子值
  seed: (seed) ->
    @seed = seed

  # 返回一個隨機(jī)整數(shù)滿足 0 <= n < @modulo
  randn: ->
    # new_seed = (a * seed + c) % m
    @seed = (@multiplier*@seed + @offset) % @modulo

 # 返回一個隨機(jī)浮點(diǎn)滿足 0 <= f < 1.0
  randf: ->
    this.randn() / @modulo

  # 返回一個隨機(jī)的整數(shù)滿足 0 <= f < n
  rand: (n) ->
    Math.floor(this.randf() * n)

  #返回一個隨機(jī)的整數(shù)滿足min <= f < max
  rand2: (min, max) ->
    min + this.rand(max-min)

討論

JavaScript和CoffeeScript都不提供可產(chǎn)生隨機(jī)數(shù)的發(fā)生器。編寫發(fā)生器對于我們來說將是一個挑戰(zhàn),在于權(quán)衡量的隨機(jī)性與發(fā)生器的簡單性。對隨機(jī)性的全面討論已超出了本書的范圍。如需進(jìn)一步閱讀,可參考Donald Kunth的The Art of Computer Programming第Ⅱ卷第3章的“Random Numbers” ,以及Numerical Recipes in C第二版本第7章的“Random Numbers”。

但是,對于這個隨機(jī)數(shù)發(fā)生器只有簡單的解釋。這是一個線性同余偽隨機(jī)數(shù)發(fā)生器,其運(yùn)行源于一條數(shù)學(xué)公式Ij+1 = (aIj+c) % m,其中a是乘數(shù),c是加法偏移量,m 是模數(shù)。每次請求隨機(jī)數(shù)時就會執(zhí)行很大的乘法和加法運(yùn)算——這里的“很大”與密鑰空間有關(guān)——得到的結(jié)果將以模數(shù)的形式被返回密鑰空間。

這個發(fā)生器的周期為232。雖然它絕對不能以加密為目的,但是對于最簡單的隨機(jī)性要求來說,它是相當(dāng)足夠的。randn()在循環(huán)之前將遍歷整個密鑰空間,下一個數(shù)由上一個來確定。

如果你想修補(bǔ)這個發(fā)生器,強(qiáng)烈建議你去閱讀Knuth的The Art of Computer Programming中的第3章。隨機(jī)數(shù)生成是件很容易弄糟的事情,然而Knuth會解釋如何區(qū)分好的和壞的隨機(jī)數(shù)生成。

不要把發(fā)生器的輸出結(jié)果變成模數(shù)。如果你需要一個整數(shù)的范圍,應(yīng)使用分割的方法。線性同余發(fā)生器的低位是不具有隨機(jī)性的。特別的是,它總是從偶數(shù)種子產(chǎn)生奇數(shù),反之亦然。所以如果你需要一個隨機(jī)的0或者1,不要使用:

# NOT random! Do not do this!
r.randn() % 2

因?yàn)槟憧隙ǖ貌坏诫S機(jī)數(shù)字。反而,你應(yīng)該使用r.rand(2)。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號