我正在用 C++ 制作游戏,它涉及用随机布尔值(是或否)填充图块,是或否由rand() % 1
. 感觉不是很随意。
我在启动时使用srand
with ctime
,但似乎正在出现相同的模式。
是否有任何算法可以创建非常随机的数字?或者关于我如何改进的任何建议rand()
?
真正的随机性通常看起来不是很随机。确实希望看到奇怪的运行。
但至少您可以立即做的一件事是避免只使用最低位。引用 C 中的数字食谱:
如果要生成 1 到 10 之间的随机整数,则应始终使用高位来执行此操作,如
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
从来没有任何类似的东西
j = 1 + (rand() % 10);
(使用低阶位)。
此外,您可能会考虑使用具有更好属性的不同 RNG。Xorshift算法是一个不错的选择。它在几行 C 代码中既快速又紧凑,并且在统计上对于几乎任何游戏都应该足够好。
The low order bits are not very random.
By using %2 you are only checking the bottom bit of the random number.
Assuming you are not needing crypto strength randomness.
Then the following should be OK.
bool tile = rand() > (RAND_MAX / 2);
除了编写另一个 PRNG 或使用库之外,您可以做的最简单的事情就是使用一次调用为您提供的所有rand()
位。大多数随机数生成器可以分解为具有一定随机性和统计特性的比特流。在该流上均匀分布的各个位不需要具有相同的属性。本质上,您在这里丢弃了 14 到 31 位的伪随机性。
您可以只缓存调用生成的数字rand()
并使用它的每一位(当然,这取决于给您的位数rand()
,这取决于RAND_MAX
)。因此,如果您RAND_MAX
是 32768,您可以按顺序使用该数字的最低 15 位。特别是如果RAND_MAX
你没有处理生成器的低位比特那么小,所以从高端获取比特不会给你带来太多好处。例如,Microsoft CRT 使用以下公式生成随机数
x n + 1 = x n · 214013 + 2531011
然后移开该结果的最低 16 位并将其限制为 15 位。所以那里的发生器没有低位。这在很大程度上适用于RAND_MAX
高达 2 31的生成器,但有时您不能指望这一点(因此可能将自己限制为 16 或 24 位,取自高阶端)。
因此,通常,只需缓存调用的结果,rand()
并按顺序为您的应用程序使用该数字的位,而不是rand() % 2
.
许多伪随机数生成器受到循环低位的影响,尤其是线性同余算法,这通常是最常见的实现。有些人建议移出最低有效位来解决这个问题。
我已经成功使用 Mersenne Twister 随机数生成器多年。其源代码可从广岛大学数学系获得。(直接链接,所以您不必阅读日语!)
该算法的优点在于:
我建议你看看你的游戏。
C++11 具有以下实现 Mersenne tittie twister 算法的方式。来自cppreference.com:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
这会产生适合模拟的随机数,而没有许多其他随机数生成器的缺点。它不适合密码学;但是密码随机数生成器的计算量更大。
还有Well equidistributed 长周期线性算法;有许多示例实现。
随机选择是或否的完美方式是切换它们。您可能不需要随机功能。
标准随机数生成器的最低位不是很随机,这是一个众所周知的问题。
People say lower-order bits are not random. So try something from the middle. This will get you the 28th bit:
(rand() >> 13) % 2
Knuth suggests a Random number generation by subtractive method. Its is believed to be quite randome. For a sample implementation in the Scheme language see here
一个可能让你的数字感觉更随机的快速方法是在每次条件if(rand() % 50==0)
为真时重新播种生成器。
使用随机数来获得好的结果,您确实需要一个结合了多个生成器结果的生成器。仅仅丢弃底部是一个非常愚蠢的答案。
与进位相乘很容易实现,并且它本身就有很好的结果,如果你有几个并将结果结合起来,你会得到非常好的结果。它也不需要太多内存,而且速度非常快。
此外,如果您重新播种太快,那么您将获得完全相同的数字。就我个人而言,我使用一个仅在时间改变时才更新种子的类。