## 问题
你需要在一定范围内生成一个随机数,但是你也需要设定生成程序以提供可预测的数据。
## 方法
写你自己的随机数生成程序。有 _很多_ 种方法去实现它。这里有个简单的示例。 _这个生成程序绝对 不适用 于加密目的!_
~~~
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测试