伪随机数


笔者最近在练习Mysql语句优化,奈何年少不懂,找不到百万级别的测试数据,只好用java随机生成数据凑合用一下,所以写下此篇博客,经测试生成500万条数据后台用了9秒,完全可以接受

1. Random

random伪随机数类在 java.util 包下,是最常用的随机数生成器,其使用线性同余公式来生成随机数,所以才说是伪随机。该类的实例是线程安全的,多线程并发使用可能会遇到争用问题,这时可用 ThreadLocalRandom 来解决这个问题,此外还有 SecureRandom 、SplittableRandom 随机生成器,这里就不扩展说明了

2. 构造方法与常用方法

类型 名字 解释
Random() 默认构造函数
Random(long seed) 有参构造,用种子创建伪随机生成器
int nextInt 返回生成器中生成表序列中的下一个伪随机数
int nextInt(int n) 返回均匀分布于区间 [0,n)的伪随机数
double nextDouble 返回下一个伪随机数 [0.0,1.0)

3. 具体分析

先看无参构造,直接上源码

// 无参构造也是调用有参构造的,那么放出有参构造,再看里面具体内容
public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

// 有参构造接收长整型种子参数
public Random(long seed) {
    // 判断是否本类
    if (getClass() == Random.class)
        // 可以看出长整型种子是Atomic原子型的,即线程安全
        // initialScramble() 是seed与两个具体数值运算,这里不给出了
        this.seed = new AtomicLong(initialScramble(seed));
    else {
        // subclass might have overriden setSeed
        // 翻译:子类可能重写setSeed方法
        this.seed = new AtomicLong();
        setSeed(seed);
    }
}

// 再回无参构造内部
// 其中 ^ System.nanoTime() 表示与系统纳秒异或运算,也就是说随机数依赖于时间
this(seedUniquifier() ^ System.nanoTime());

private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
private static long seedUniquifier() {
    // L'Ecuyer, "Tables of Linear Congruential Generators of
    // Different Sizes and Good Lattice Structure", 1999
    // 翻译:不同大小结构良好的线性同余生成元表,
    for (;;) {
        long current = seedUniquifier.get();
        long next = current * 181783497276652981L;
        // 用到了CAS轻量锁
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}

再看nextInt方法,有参的方法用逻辑运算把范围指定,这里就不介绍了

public int nextInt() {
    return next(32);
}

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;  // 都是具体的值位运算
    } while (!seed.compareAndSet(oldseed, nextseed));  // 改变值
    return (int)(nextseed >>> (48 - bits));     // 可能这些位运算就是线性同余把
}

简单使用

Random r1 = new Random();
Random r2 = new Random();
Random r3 = new Random();
Random r4 = new Random(1000);
Random r5 = new Random(1000);

System.out.println(r1.nextInt());
System.out.println(r2.nextInt());
System.out.println(r3.nextInt(100));
System.out.println(r4.nextInt());
System.out.println(r5.nextInt());
491030142
2021835847
49
-1244746321
-1244746321

从结果和源码可以看出:

  • 这里补充一下seed是final类型,线程更安全
  • 给定seed之后,伪随机数的序列是确定的
  • 而没有给seed因为依赖于变化的时间,所以每次的序列是不确定的
  • 常用 new Random.nextInt(int n)来生成伪随机数

4. Math.random

我们最常用还是这个函数,静态调用方便简单

// 底层还是用了Random类
public static double random() {
    return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}

// 新建一个依赖时间的随机数生成器
private static final class RandomNumberGeneratorHolder {
    static final Random randomNumberGenerator = new Random();
}

// 位运算加强随机
public double nextDouble() {
    return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}

从源码可以看出:

  • 这个类方便我们使用伪随机数,每次调用就新建一个Random类
  • 也知道区间为 [0.0,1.0)

生成给定范围的伪随机数

// 给定范围
int min = 10;
int max = 15;

// 生成伪随机小数
double num = Math.random();

// 范围逻辑运算,想一下很简单的
int rs = (int)(num * (max - min + 1) + min);

System.out.println(rs); // 需要整数的位数

5. 这里贴一下生成测试数据中密码的逻辑

// 密码字符范围
String range = "0[email protected]#$%^&*()_+[];',.<>?:{}|";

// 生成100个伪随机密码
for(int i = 0; i < 100; i++){

    // 字符串
    StringBuffer bf = new StringBuffer();

    // 密码长度8~20
    int len = (int)(Math.random() * (20 - 8 + 1) + 8);
    for(int j = 0; j < len; j++){
        int index = new Random().nextInt(range.length());
        bf.append(range.charAt(index));
    }
    System.out.println(bf.toString());
}
[email protected]<s
|4z$1sDIDRt_o{PR
H_}z;A9;K74amjb2r
O;*89#b!|4w|;z?~
s+EmeTCdpJ9?W8,lNNl|
o2#[email protected],hFT
{+})BECM.Jf|&
// 完全看不懂,还可以加上MD5加密

原文地址:https://www.cnblogs.com/Howlet/p/12319487.html

时间: 2024-10-12 10:12:51

伪随机数的相关文章

java 伪随机数类

/* * Random:产生随机数的类 *  * 构造方法: *  public Random():没有给种子,用的是默认种子,是当前时间的毫秒值 * public Random(long seed):给出指定的种子 * * 给定种子后,每次得到的随机数是相同的. * * 成员方法: *  public int nextInt():返回的是int范围内的随机数 * public int nextInt(int n):返回的是[0,n)范围的内随机数 */示例://定义伪随机数     Rando

伪随机数算法(一)

伪随机数概念在我大学一年级接触C语言基础的时候就听说过,并熟练掌握C语言中rand()函数的使用方法.不过,当时我对伪随机数的认识基本也就停留在百度百科那种小白水平,最多就知道老师说我们用的随机数是假的,是通过某种算法实现的.最近学习计算物理学讲到Monte Carlo方法时,通过课本和互联网才算真正意义上理解了什么是伪随机数.借此文好好总结一下吧! 一.随机数的分类 在计算物理学中,随机数被准确地分成了三类:真随机数.准随机数.伪随机数.那么这三种的区别是什么呢?拷贝一段书上的定义(我觉得写的

使用线性同余法生成伪随机数/序列(C++实现)2

以下是网上关于随机数生成的一类说法: 在计算机上可以用物理方法来产生随机数,但价格昂贵,不能重复,使用不便.另一种方法是用数学递推公式产生,这样产生的序列与真正的随机数序列不同,所以称为伪随机数或伪随机序列,只要方法和参数选择合适,所产生的伪随机数就能满足均匀性和独立性,与真正的随机数具有相近的性质. 以下是一个使用了线性同余的递推公式: Xt = (X0 * 17 + 29) mod 500 线性同余中的线性,是指"线性"表示方程中 x 的次数是一次,mod 取余运算符则体现了&qu

[计算机漫谈]伪随机数生成方法

大家好.今天说点儿关于程序设计过程中产生随机数的方法. (一)JAVA伪随机数生成方法 随机数在程序设计过程中,特别是在实践环境模拟和测试等领域中得到很广泛的应用,我们在编程的过程中也时不时需要使用到随机数.计算机中的随机数,并不是真正的随机数,而是叫做"伪随机数",是计算机通过某种特别算法模拟产生的. 在JAVA语言中,我们可以通过Math类的random方法产生区间[0,1)的随机数,若要产生[a,a+b)之间的伪随机数,可以通过语句 a + b * Math.random();

Atitit.手机验证码的破解---伪随机数

1. 手机验证码几乎都是伪随机数1 2. 伪随机数1 2.1. 生成方法编辑1 2.2. 随机数的计算方法在不同的计算机中是不同的,即使在相同的计算机中安装的不同的操作系统中也是不同的.2 2.3. 现在,我们明白随机种子是从哪儿获得的 随机种子来自系统时钟,2 2.4. .计算机的伪随机数是由随机种子根据一定的计算方法计算出来的数值.所以,只要计算方法一定,随机种子一定,那么产生的随机数就是固定的.3 2.5. 只要用户或第三方不设置随机种子,那么在默认情况下随机种子来自系统时钟.3 3. 伪

伪随机数的产生

应用:随机数或者伪随机数的产生在大量的密码函数中都有广泛的应用. 要求:随机性和不可预测性 1.随机性有两个评价标准:分布均匀性和独立性 a) 分布均匀性指的是0和1出现的概率大致相等 b) 独立性指的是序列中任何子序列不能由其他子序列推导出 遗憾的是,没有可靠的方法表明一个序列的独立性好,只能证明一个序列不具有独立性.因此只好多测测,来回多次仍然表现不错的话,就姑且当它独立性不错啦. 2.不可预测性是指每个数都统计独立于其他数,因而不可预测.但是真正的随机数序列很少用,一般看上去随机的随机数序

伪随机数生成方法

大家好.今天说点儿关于程序设计过程中产生随机数的方法. (一)JAVA伪随机数生成方法 随机数在程序设计过程中,特别是在实践环境模拟和测试等领域中得到很广泛的应用,我们在编程的过程中也时不时需要使用到随机数.计算机中的随机数,并不是真正的随机数,而是叫做"伪随机数",是计算机通过某种特别算法模拟产生的. 在JAVA语言中,我们可以通过Math类的random方法产生区间[0,1)的随机数,若要产生[a,a+b)之间的伪随机数,可以通过语句 a + b * Math.random();

使用线性同余法生成伪随机数/序列(C++实现)

最近朋友提出一个问题,自己编写函数生成随机数,一开始没有认真思考,后来想了一下,如果是学习过计算机密码学,应该很快就能设计出一些算法,这里使用了数论领域的相关知识--线性同余法简单实现了生成随机数算法. 以下是网上关于随机数生成的一类说法: 在计算机上可以用物理方法来产生随机数,但价格昂贵,不能重复,使用不便.另一种方法是用数学递推公式产生,这样产生的序列与真正的随机数序列不同,所以称为伪随机数或伪随机序列,只要方法和参数选择合适,所产生的伪随机数就能满足均匀性和独立性,与真正的随机数具有相近的

一个简单的伪随机数发生算法(转)

源:一个简单的伪随机数发生算法 //此代码纯属交流目的,如用作安全领域,后果自负 #include <stdint.h> #include <stdlib.h> //! \brief random seed static uint16_t s_hwRandomSeed = 0xAA55; static uint8_t s_chRandomTable[] = { 0x12,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF, 0xF1,0xE2,0xD3,0xC4,

关于用 random 生成伪随机数的一个手笔

我在想还要不要写什么文字.确实不需要太多的文字描述吧. 前奏插一个小话题,之前在网上看到这样的冷笑话(有图的),一个程序猿调试个程序,早上怀疑某某地方的错误,下午怀疑某某地方的错误,晚上怀疑某某地方可能错了,睡觉了还是辗转反侧难以入眠.第二天早上,再看看代码的时候,无意中找到了bug,漏下了逗号“,“,哈哈冷笑话. 我这次也是疏忽了.在一个网站的项目中,用random去生成随机数,作为上传文件的名称.当然在需要用户上传的文件中是不容易遇到这个bug的.但是在做爬虫下载文件也用这个random生成