## 問題
你需要在一定范圍內生成一個隨機數,但是你也需要設定生成程序以提供可預測的數據。
## 方法
寫你自己的隨機數生成程序。有?_很多_?種方法去實現它。這里有個簡單的示例。?_這個生成程序絕對 不適用 于加密目的!_
~~~
class Rand
# if created without a seed, uses current time as seed
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
# sets new seed value
seed: (seed) ->
@seed = seed
# return a random integer 0 <= n < @modulo
randn: ->
# new_seed = (a * seed + c) % m
@seed = (@multiplier*@seed + @offset) % @modulo
# return a random float 0 <= f < 1.0
randf: ->
this.randn() / @modulo
# return a random int 0 <= f < n
rand: (n) ->
Math.floor(this.randf() * n)
# return a random int min <= f < max
rand2: (min, max) ->
min + this.rand(max-min)
~~~
## 討論
JavaScript 和 CoffeeScript 并沒有提供可以預先設置的隨機數生成程序。寫你自己的隨機函數將主要練習用一種用簡單隨機生成程序去生成大量隨機數。關于隨機過程的討論超出了這本Cookbook的范疇。有興趣的同學可以閱讀Donald Knuth的?_The Art of Computer Programming_?的第二篇第三章節 “Random Numbles”,以及?_Numerical Recipes in C_?第二版第七章 “Random Numbers”。
然而,一個關于隨機數生成程序的簡單解釋是有序。它就是Linear Congruential Pseudorandom Number Generator(線性全等偽隨機數產生器)。LCPRNG在數學上的表現形式是 Ij+1?= (aIj+c) % m,在公式中,a是乘數,c是偏移常數,m是模數。
每請求一次隨機數,一個很大規模的乘法器和加法器在運行——”很大”是相對于主要的區間而言——并且結果數被模除后,分布在主要的區間中。
這種隨機數生成器的位數范圍是232,如果以加密為目的,這幾乎不可以接受,要不是大多數簡單沒有規則的需求,它足夠適用。在重復自己之前,`randn()`?會覆蓋整個區間,而下一個隨機數由前一個決定。
如果你想粗略的修補一下隨機程序,?_強烈_?建議你閱讀 Knuth 的?_The Art of Computer Programming_?的第三章。隨機數生成程序很容易被搞砸,而且 Knuth 從一個糟糕的案例中解釋怎樣去判斷一個好的隨機數生成程序(RNG, Random Number Generator)。
避免把這個生成的結果進行模除。如果你需要一個整數的范圍,用除法。線性全等生成器在數據位數很小時并不隨機。這種算法特別在當偶數種子的時候,會產生奇數。因此,如果你需要一個0或1的隨機數,?**不要**?使用下面的方法:
~~~
# NOT random! Do not do this!
r.randn() % 2
~~~
因為你幾乎可以肯定不會得到隨機位數。用`r.randi(2)`代替上面的方法。
- 貢獻
- 作者
- 授權協議
- 1、Syntax
- 在服務端和客戶端重用代碼
- For循環
- 嵌入JavaScript代碼
- 值域
- 2、Classes and Objects
- 類方法和實例方法
- CoffeeScript式的Type函數
- 鏈式調用
- 克隆對象(深度克隆)
- 不存在就賦值為對象字面量
- 類變量
- 3、Strings
- 分割字符串
- 字符串匹配
- 查找子字符串
- 讓整個字符串小寫
- 大寫整個字符
- 去掉字符串首尾的空白
- 生成唯一的ID
- 首字母大寫
- 重復字符串
- 字符串插值
- 4、Arrays
- Python式的Zip函數 Python-like Zip Function
- 數組去重 Removing Duplicate Elements from Arrays
- 基于數組構建字典對象 Creating a dictionary Object from an Array
- 數組轉成字符串 Creating a String from an Array
- 檢查每一個元素 Testing Every Element
- 數組最大值
- 過濾數組 Filtering Arrays
- 定義區間數組 Define Ranges Array
- 轉置數組 Reversing Arrays
- 化簡數組 Reducing Arrays
- 使用數組來做值交換 Using Arrays to Swap Variables
- 列表解析 List Comprehensions
- 檢查值的類型是否是數組
- 連接數組
- 攪亂數組中的元素 Shuffling Array Elements
- 數組映射 Mapping Arrays
- 5、Dates and Times
- Calculate Phase of the Moon for a Date
- 找出某月的最后一天是幾號 Finding the Last Day of the Month
- 獲取兩個日期相差的天數 Get Days Between Two Dates
- 計算復活節島日期 Calculate the Date of Easter Sunday
- 計算感恩節的日期(美國和加拿大) Calculate the Date of Thanksgiving (USA and Canada)
- 計算上一個(下一個)月份 Finding Last (or Next) Month
- 6、Math
- 快速逆平方根
- 一個隨機整數的函數
- 更快的斐波那契算法
- 生成可預測的隨機數
- 弧度與度轉換
- 生成隨機數
- 數學常數
- 7、Functions
- 反抖動函數 Debounce Functions
- 參數數組化 Splat Arguments
- 當函數調用的括號不可以省略時 When Function Parentheses Are Not Optional
- 遞歸函數 Recursive Functions
- 8、Metaprogramming
- 擴展內置對象 Extending Built-in Objects
- 檢測并創建缺失的函數 Detecting and Creating Missing Functions
- 9、jQuery
- 回調綁定
- 創建jQuery插件
- AJAX
- 10、Ajax
- 不依賴jQuery的Ajax請求 Ajax Request Without jQuery
- 11、Regular Expressions
- 替換子字符串 Replacing Substrings
- 使用定點 Using Heregexes
- 使用HTML字符實體替換HTML標簽 Replacing HTML Tags with HTML Named Entities
- 搜索子字符串 Searching for Substrings
- 12、Networking
- 簡單的服務器
- 雙向客戶端
- 最簡單的HTTP客戶端
- 最簡單的HTTP服務器
- 簡單的客戶端
- 雙向服務端 Bi-Directional Server
- 13、Design Patterns
- 命令模式
- 單例模式
- 策略模式 Strategy Pattern
- 建造者模式 Builder Pattern
- 備忘錄模式 Memento Pattern
- 解釋器模式 Interpreter Pattern
- 裝飾者模式
- 橋接模式
- 工廠方法模式
- 14、Databases
- MongoDB
- SQLite
- 15、Testing
- 使用Jasmine測試