在 C++ 中通过掷骰子生成随机值
计算机无法猜测数字。每次机器生成一个随机数时,它要么是某种按位运算的乘积,要么是数值因子(即时间、序列)的导数。
使用上述方法的问题是,如果重复足够多次,它们将产生相同的结果集。
这就是为什么不建议将用于生成随机数的传统算法用于加密实践的原因。结果很容易预测。
在预测随机性时,掷骰子是一项相当简单的任务。在本文中,读者将了解计算机中的随机性以及如何使用 C++ 从简单的掷骰子中获取随机结果。
在 C++ 中通过掷骰子生成随机数
伪随机生成器是一种生成看似随机的数字的机器。相反,它们是完全可以预测的。
这是因为传统的随机数生成器使用种子。简单来说,种子是一个依赖于时间或数值分量的单射函数。
例如,通过在 x(0)
上重复应用内射函数(称为 f(x0)
)为给定种子 x(0)
产生的结果,因此 fn(x0)
不同于 fn-1(x0)
或 fn+1(x0)
,其中 fn
表示函数结构 n
次。
换句话说,f(x)
包含与之前的几乎无关的大跃迁。
种子使用时间在 C++ 中为掷骰子创建随机数
在大多数情况下,生成的种子取决于时间因素。这意味着单射函数会考虑时钟中的当前秒数。
让我们看一个例子来更好地理解它。
unsigned main_seed;
main_seed = time(0);
srand(main_seed);
在这里,一个无符号变量 main_seed
被初始化;此变量用于存储当前时间。srand()
是一个从种子生成结果的 C++ 函数。
生成种子后,rand()
函数可以用作种子,以使用线性方程生成随机值。
除非涉及现代 CPU,否则使用时间因子来获取独特的种子似乎是一种很好的做法,因为它们以纳秒为单位处理进程,这会在随机性方面破坏整个功能。
在大多数情况下,生成的种子取决于时间因素。这意味着单射函数会考虑时钟中的当前秒数。
因为时钟并不像人们想象的那么快,如果 srand(time)
在一秒钟内被多次使用,同一个种子会被多次获得。因此,生成的随机数集将是相似的。
这可能是一个(重大)问题,尤其是在分组密码程序中。在后一种情况下,人们购买了大量基于实时物理形容词的发生器,例如大气数据中的温度变化等,或者最近测量量子比特,例如偏振光子如何叠加的因素.
在 C++ 中使用任意数为掷骰子创建随机数的种子
下面的示例演示了一个使用数字的伪数生成器。
static unsigned long int rand_num = 2;
int rand(void) // The ceiling limit is kept at 32767
{
rand_num = rand_num * 113546545 + 12345;
return (unsigned int)(rand_num / 65536) % 32768;
}
void srand(unsigned int main_seed) // seed is stored inside variable main_seed
{
rand_num = main_seed;
}
一个无符号整数变量 rand_num
用值 2
初始化。上述程序中有两种方法 - rand
和 srand
。
rand
方法将一个新数字连接到初始化值。随着种子上限的设置,rand
的 mod 和上限将返回一个低于上限的数字。
从此方法返回的最终结果被类型转换为无符号整数。
srand()
方法将值从 rand_num
传递给种子变量 main_seed
。
使用上述方法的缺点
可以看出,执行 srand(time(0))
或为种子取任意值总是会在 rand()
上返回新的数字,这些数字取决于种子。但是在几百万之后,数字会重复。
种子控制按顺序创建哪些随机数,即 srand(1)
在第一次调用 rand()
时几乎总是产生相同的值,第二次调用 rand()
时产生相同的数字,等等。
换句话说,如果在每次 rand()
调用之前重新播种相同的种子,则输出始终是相同的随机数。因此,在一秒钟内使用 time(0)
播种几次将导致重新播种后所有随机数都相同。
它必须在几个周期后重复,但 srand
参数定义了模式。C++ rand
不适合加密,因为知道种子有助于黑客估计下一个数字。
使用 C++ 生成类似于掷骰子的随机值
该程序使用时间生成的种子来生成 1 到 6 范围内的随机数。
导入包
本程序需要三个导入包:
iostream
cstdlib
- 用于时间函数和 rand 操作time
- 时间函数的头包
iostream
被导入用于程序中的输入输出操作。另一个包 cstdlib
用于 C++ 程序中的基本控制操作。
第三个包是 time
包,将用于为程序创建种子。
根据 C++ 中的骰子生成值
一个骰子有 6 个单独的值。该程序的作用必须是在该范围内生成一个随机自然数,该自然数可能会在随后的掷骰中重复,但总体结果必须看起来完全随机。
初始化三个变量以找到结果。变量 floor
和 ceiling
存储骰子的最低和最高值,变量 outcome
用于查找随机数。
int outcome;
int l_limit = 1;
int h_limit = 6;
最终值是使用 rand()
函数生成的,将结果限制在上限和下限范围内。
outcome = rand() % (max - min + 1) + min;
最后,返回变量 roll
。
int outcome;
int l_limit = 1; // floor or lower limit of a die
int h_limit = 6; // ceiling or higher limit of a die
outcome = rand() % (h_limit - l_limit + 1) + l_limit;
return outcome;
使用时间生成种子并显示结果
程序在 srand()
函数中获取当前时间并将其传递给 rand()
函数。应用程序使用 Droll()
方法中的 rand()
函数来查找规定范围内的自然数。
srand(time(0));
产生种子后,必须调用 Droll()
方法,并打印结果。
传统上,三个模具辊总是被认为是一套完整的。该技术重复 3 次以验证随机性。
我们需要将 Droll()
方法放在 for
循环中,并在 print
语句中调用 3 次。最终结果是一个由掷骰子生成的 3X3 伪随机数矩阵。
for (int i = 0; i < 3; i++) {
std::cout << Droll() << " ";
std::cout << Droll() << " ";
std::cout << Droll() << std::endl;
}
让我们将所有内容放在程序中并查看结果。
#include <cstdlib>
#include <iostream>
#include "time.h"
int Droll() {
int outcome;
int l_limit = 1; // floor or lower limit of a die
int h_limit = 6; // ceiling or higher limit of a die
outcome = rand() % (h_limit - l_limit + 1) + l_limit;
return outcome;
}
int main() {
srand(time(0));
for (int i = 0; i < 3; i++) {
std::cout << Droll() << " ";
std::cout << Droll() << " ";
std::cout << Droll() << std::endl;
}
}
输出:
3 1 2
6 1 3
4 5 4
--------------------------------
Process exited after 0.00784 seconds with return value 0
Press any key to continue . . .
结论
本文解释了伪数生成器的基础知识。读者已经看到了生成随机数的不同方法及其优缺点。
给出了一个 C++ 程序,以使概念清楚地表明随机数是如何在范围内生成的,以及如何使用计算机程序来模拟掷骰子。