http://uh.9ria.com/space-12147-do-blog-id-4007.html
计算机是无法计算“真”随机数的,而只能计算“伪”随机数。所谓伪随机数,并不是按投硬币的方法来实现,而是从一个特定数开始,通过算法从一个“随机值”计算另一个“随机值”,并保证两者关系尽可能看上去混乱而且最终在区间内数值分配均匀。
因为伪随机数是按上一个数作为参数计算出来的,所以它需要一个初值,而这个初值则被称为“随机种子”。一般这个随机种子都是取的当前系统时间。也就是说,两台电脑在同一毫秒初始化并生成的第一个随机数一定是同一个。
因为伪随机数仅仅是计算得到的,它除了随机种子外并没有偶然性。如果你给定一个随机种子,通过这个随机种子计算出的所有“随机数”一定都是一样的。
一般的语言其实都是有设置“随机种子”的功能的,但AS3没有,所以只能自己实现随机算法。如果想利用伪随机数的特性,可以用下面这个类来生成随机数(创建后用nextInt方法,参数是大小范围)
http://code.google.com/p/ghostcat/source/browse/trunk/GhostCat/src/ghostcat/util/RandomSeed.as
下面我就来说说利用这个特性能做什么。
比如我们需求要显示一个电影院的所有观众,他们有多种类型,会坐在不同的地方,不同的进入和离开时间。而服务端并不关心影院的具体情况,只需要你显示出正确的人数即可。那么,它就不需要计算出所有的信息并传递到客户端,而是让客户端自己随意生成,也就是使用随机数生成。但问题是,如果简单使用随机数生成而不保存状态,关闭游戏再进,或者在别的玩家眼里,看到的影院状态就会完全不同(除了总人数)
这时候就可以利用伪随机数。然服务端生成一个随机数保存起来来作为随机种子,客户端使用这个种子来生成自己需要的随机数序列。因为同样种子生成的随机数序列一定是相同的,那么就可以重现第一次生成影院状态的过程,并得到相同的结果。
package ghostcat.util
{
import flash.utils.ByteArray;
/**
* 伪随机数
* @author flashyiyi
*
*/
public class RandomSeed
{
private static const MULTIPLIER_HIGH:uint=5;
private static const ADDEND:uint=11;
private static const MULTIPLIER_LOW:uint=58989;
private static const MULTIPLIER_MID:uint=57068;
private var seedHigh:uint;
private var seedLow:uint;
private var seedMid:uint;
private static var seedExtra:uint=2353648897;
public function RandomSeed(high:uint=0x80000000, low:uint=0)
{
if (high == 0x80000000 && low == 0)
{
var bytes:ByteArray = new ByteArray();
bytes.writeDouble(new Date().time);
bytes.position = 0;
high = bytes.readUnsignedInt() + seedExtra;
low = bytes.readUnsignedInt() + (high >>> 16);
seedExtra++;
}
setSeed(high, low);
return;
}
public function setSeed(high:uint, low:uint):void
{
this.seedHigh = high & 65535 ^ MULTIPLIER_HIGH;
this.seedMid = low >> 16 & 65535 ^ MULTIPLIER_MID;
this.seedLow = low & 65535 ^ MULTIPLIER_LOW;
return;
}
private function next(max:uint):uint
{
var v2:Number = 0;
var v3:Number = 0;
var v4:Number = 0;
v4 = seedLow * MULTIPLIER_LOW;
v2 = seedLow * MULTIPLIER_HIGH + seedMid * MULTIPLIER_MID + seedHigh * MULTIPLIER_LOW;
v3 = seedLow * MULTIPLIER_MID;
v2 = v2 + (v3 >>> 16);
v3 = v3 & 65535;
v3 = v3 + seedMid * MULTIPLIER_LOW;
v2 = v2 + (v3 >>> 16);
v3 = v3 & 65535;
v3 = v3 + (v4 >>> 16);
v2 = v2 + (v3 >>> 16);
v4 = v4 & 65535;
v3 = v3 & 65535;
v2 = v2 & 65535;
v4 = v4 + ADDEND;
v3 = v3 + (v4 >>> 16);
v2 = v2 + (v3 >>> 16);
v4 = v4 & 65535;
v3 = v3 & 65535;
v2 = v2 & 65535;
seedLow = v4;
seedMid = v3;
seedHigh = v2;
if (max == 0)
return 0;
return (v2 << 16 | v3) >>> 32 - max;
}
public function nextInt(max:int):uint
{
var v2:Number = 0;
var v3:Number = 0;
if (max == 0 || !((max & 2147483648) == 0))
throw new Error();
if ((max & -max) == max)
{
v2 = 0;
if ((max & 4294901760) != 0)
{
v2 = v2 + 16;
}
if ((max & 4278255360) != 0)
{
v2 = v2 + 8;
}
if ((max & 4042322160) != 0)
{
v2 = v2 + 4;
}
if ((max & 3435973836) != 0)
{
v2 = v2 + 2;
}
if ((max & 2863311530) != 0)
{
v2 = v2 + 1;
}
return next(v2);
}
do
{
v2 = next(31);
v3 = v2 % max;
}
while ((v2 - v3 + max - 1) < 0);
return v3;
}
}
}