生成随机数,无需使用任何外部函数

2022-09-02 11:32:42

这是我最近参加的一次采访中提出的问题。

据我所知,两个数字之间的随机数可以生成如下

public static int rand(int low, int high) {
    return low + (int)(Math.random() * (high - low + 1));
}

但在这里,我使用Math.random()来生成一个介于0和1之间的随机数,并用它来帮助我在低和高之间生成。有没有其他方法可以直接使用外部功能?


答案 1

典型的伪随机数生成器基于以前的数字计算新数字,因此从理论上讲,它们是完全确定的。唯一的随机性是通过提供一个好的种子(随机数生成算法的初始化)来保证的。只要随机数不是很安全关键(这需要“真实”的随机数),这种递归随机数生成器通常可以满足需求。

一旦提供了种子,递归生成就可以在没有任何“外部”函数的情况下表示。有几种算法可以解决这个问题。一个很好的例子是线性同余生成器

伪代码实现可能如下所示:

long a = 25214903917;   // These Values for a and c are the actual values found
long c = 11;            // in the implementation of java.util.Random(), see link
long previous = 0;

void rseed(long seed) {
    previous = seed;
}

long rand() {
    long r = a * previous + c;
    // Note: typically, one chooses only a couple of bits of this value, see link
    previous = r;
    return r;
}

您仍然需要为此生成器设定一些初始值。这可以通过执行下列操作之一来完成:

  • 使用类似当前时间的东西(在大多数非安全关键情况下(如游戏)都很好)
  • 使用硬件噪声(适用于安全关键随机性)
  • 使用常量数字(有利于调试,因为您始终获得相同的序列)
  • 如果您不能使用任何函数并且不想使用常量种子,并且如果您使用允许这样做的语言,则还可以使用一些未初始化的内存。例如,在C和C++中,定义一个新变量,不要为其分配某些内容,并使用其值为生成器设定种子。但请注意,这远非“好种子”,而只是满足您要求的黑客。切勿在实际代码中使用它。

请注意,没有一种算法可以在不访问某些外部源(如系统环境)的情况下,为具有相同输入的不同运行生成不同的值。每个种子良好的随机数生成器都利用了一些外部源。


答案 2

在这里,我建议一些带有评论的来源可能会对您有所帮助:

  • 系统时间:单调在一天内差随机。快速、简单。
  • 鼠标点 :随机但在独立系统上没有用。
  • 原始套接字/本地网络(数据包的信息部分):良好的随机技术和耗时 - 可以对攻击模式进行建模以减少随机性。
  • 一些带有排列的输入文本:快速,通用的方式和好(在我看来)。
  • 由于键盘、磁盘驱动器和其他事件而中断的时间:常用方法 - 如果不小心使用,容易出错。
  • 另一种方法是馈送模拟噪声信号:例如温度。
  • /proc 文件数据:在 Linux 系统上。我觉得你应该用这个。

    /proc/sys/kernel/random:此目录包含控制文件操作的各种参数。/dev/random

    字符特殊文件和(自)提供了内核随机数生成器的接口。/dev/random/dev/urandomLinux 1.3.30

    试试这个逗号:

    $cat /dev/urandom   
    

    $cat /dev/random
    

    您可以编写从此文件读取的文件读取函数。

    阅读(还建议):来自 /dev/urandom 的兰特对于登录密钥是否安全?

`