不知道你有没有参与过公司年会,
互联网公司的年会抽奖环节正常都是用自己写的软件抽奖的, 然后我们经常会看到每年年会期间有些公司会在年会上现场 review抽奖代码, 基本都是觉得他丫的这是不是真的随机抽奖?
其实真正的随机是不存在的, 至少在代码层面不存在, 因为随机数在代码层面都是用算法来计算, 而算法只能通过优化来确保随机数在某个空间上均匀分布。
打个比方, 如果在0 - 100 里面生成 一万个随机数, 那么结果应该是这一万个数均匀分布在 0 - 100 这个区间, 也可以理解为每个数出现的次数基本一致。 而伪随机的话就可能出现很多情况了, 比如正态分布,随机数集中在中间的区间。
为了让结果尽可能接近理想情况, 我们需要让每一次生成的结果和之前的结果有关联。
这里就有个种子的概念, 以Java的 Random类来说, 生成 Random对象有两种方式,
Random r1 = new Random();
Random r2 = new Random(100);
System.out.println(r1.nextInt(10));
System.out.println(r2.nextInt(10));
第二种就是用种子 100来生成一个随机对象。
这里的原理是, Random会用算法把 100 转换成随机数区间 0 - 10 中某一个点, 之后生成的随机数都会与上一次结果有关而且呈均匀分布。
虽然这样子可以生成接近理想的随机数, 但是也有个严重的问题, 如果我们用同样的种子去生成随机数的话, 就可能导致结果是可以预测的。
来看看下面这段代码, 你可以把它放到自己的环境上运行,看结果是不是跟我的一样。
import java.util.Random;
public class RandomTest {
public static void main(String[] args) {
Random r1 = new Random();
Random r2 = new Random();
Random r3 = new Random(100);
Random r4 = new Random(100);
System.out.println(r1.nextInt(10));
System.out.println(r1.nextInt(10));
System.out.println(r2.nextInt(10));
System.out.println(r2.nextInt(10));
System.out.println("<------------>");
System.out.println(r3.nextInt(10));
System.out.println(r3.nextInt(10));
System.out.println(r4.nextInt(10));
System.out.println(r4.nextInt(10));
}
}
我这边的输出结果是
9 3 2 0 <------------> 5 0 5 0
可以看看你的代码在分割线下面生成的随机数是不是跟我一样。 如果没有意外的话, 你会得到跟我一致的结果。 这里的原因就是种子, 当选用同样的种子时,在同样的算法下,在相同区间中生成的随机数序列是一致的, 也就是说如果年会的抽奖算法用了某一个固定的种子, 那么结果早在年会前就确定了。
所以想要生成一个尽可能完美的结果的话, 种子要尽可能的随性, 比如取系统当前时间,再取参与人数取模或者取余, 这样才能保证随机数的不确定性。