Arduino 的新手。 "Random"值在复位时重复
New to arduino. "Random" values are repeating upon reset
我正在arduino基于C++的环境中编写轮盘游戏,该游戏闪烁LED以表示球盘旋和停止。我的问题是球每次都停在同一位置。我正在使用randomSeed(analogRead(0))与random(min,max)结合使用来生成一个随机数。这个随机数代表我的球"进入"的位置。但是,当我重置我的arduino时,我得到了完全相同的结果。有谁知道我的问题可能在哪里?
一些重要注意事项
-我在全局范围内调用随机,因为我想要我的轮盘游戏("球"进入的地方)的单个随机起点。当这两者协同工作时,在设置中使用 randomSeed 并在全局范围内使用 random 会导致问题吗?我对"setup"如何与 arduino 中的其余代码交互不熟悉。
-我生成的随机数在非常小的范围内(0-4)。但是我已经多次重置我的 arduino,并连续大约 2 次将 30 作为第一个数字。
我也尝试在全局范围内调用 randomSeed 而不是设置,但当我这样做时,我遇到了以下错误。 " 退出状态 1 在"("令牌之前进行预期的构造函数、析构函数或类型转换 ">
如果我可以提供更多细节,或者如果有人知道有关类似问题的帖子,请告诉我。
Arduino代码往往有3个部分。设置、循环和两者外部。我运行了一些测试,发现当随机在循环和设置之外时,对 randomSeed() 的更改不会影响随机生成的数字。但是,当随机处于循环中时,它会对来自 randomSeed 的更改做出反应。为什么?有没有办法让随机和随机种子一起工作,当随机种子在设置中并且随机在全局中被调用时?
以下是我关于如何在Arduino或任何微控制器上实现随机数生成器的建议:
-
仅在启动时播种随机数生成器(在 Arduino 中为
setup()
)。
-
使用计时器消耗随机数,和/或在空闲时使用随机数。
这样,即使上电后的状态是可预测的,状态也会非常迅速地变化,并且变得不可预测(除非以微秒的间隔非常密切地监视微控制器状态)。
-
使用异或(
^
)来混合来自至少具有一定随机性的源的熵,例如基于雪崩噪声的硬件源。为了获得最佳效果,请仅偶尔进行。我个人会将熵馈送到一个单独的伪随机数生成器,并将其输出混合到主生成器状态。
-
使用人工输入(按钮按下等,通过高分辨率计时器)作为熵的来源。
也就是说,以非常高的分辨率测量例如连续按下按钮之间的时间,并使用几个最低有效位作为熵混合到伪随机数生成器状态中。
只需按几下按钮,伪随机数生成器的内部状态基本上是不可预测的。
-
使用电池备份的SRAM(通常作为实时时钟模块的一部分提供)来存储下一次启动的种子状态。
从技术上讲,您也可以为此使用EEPROM或Flash,但由于它们的写入周期有限,因此我不建议为此使用它们。
正如我在其他帖子中提到的,我个人不信任内置的伪随机数生成器,而是实现一种已知的基于线性反馈移位生成器的生成器(Xorshift变体或Mersenne Twister)。它们是众所周知的,并且它们的输出随机性具有特征。
对于基于 Arduino 的游戏,我可能会使用 Xorshift128 作为随机数生成器本身,并使用 Xorshift64* 从硬件源获取熵,并时不时地使用它的输出来扰乱主生成器状态(例如,在按下按钮或类似场合;每秒少于一次)。
我会确保即使在空闲时,生成器的状态也是先进的(通过"消耗"伪随机数;只是将它们扔掉),因此物理世界的时间将成为生成序列的主要因素。
各种微控制器具有不同的定时器和可用的硬件功能,因此我将实现的确切代码肯定取决于所使用的硬件。 不幸的是,这意味着代码在硬件上不是那么可移植;即使是微小的、看起来无害的变化也可能意味着输出变得非常可预测。 我可以为 Arduino Leonardo/Arduino Pro Micro(均基于 ATmega32u4 微控制器)写一个示例,因为我手头有一个,但如果您使用的是其他微控制器,代码可能会很有趣,但如果您试图将其移植到另一个硬件架构而不知道其细节和行为,则最糟糕的是误导。
要生成范围内的伪随机整数,我建议使用排除方法,而不是模(%
)方法。 排除法确保均匀分布;模法可以对范围较小端附近的某些值产生小的偏差。
排除方法的想法很简单。您准确获取覆盖范围所需的位数,但排除范围之外的值。平均而言,您可能会消耗多达两倍的随机数位,但使用像 Xorshift 这样的快速生成器,这绝对不是问题。
固定 32 位有符号整数范围函数的一般模式是
static inline int32_t rndrange(void)
{
uint32_t u;
do {
u = random32() >> SHIFT;
} while (u > LIMIT);
return u + MINIMUM;
}
其中random32()
返回统一的伪随机 32 位无符号整数,MINIMUM
是函数可以返回的最小整数,MINIMUM + LIMIT
是函数可以返回的最大整数 (LIMIT = MAXIMUM - MINIMUM
),SHIFT
31 if LIMIT == 1 ║ 15 LIMIT <= 131071
30 LIMIT <= 3 ║ 14 LIMIT <= 262143
29 LIMIT <= 7 ║ 13 LIMIT <= 524287
28 LIMIT <= 15 ║ 12 LIMIT <= 1048575
27 LIMIT <= 31 ║ 11 LIMIT <= 2097151
26 LIMIT <= 63 ║ 10 LIMIT <= 4194303
25 LIMIT <= 127 ║ 9 LIMIT <= 8388607
24 LIMIT <= 255 ║ 8 LIMIT <= 16777215
23 LIMIT <= 511 ║ 7 LIMIT <= 33554431
22 LIMIT <= 1023 ║ 6 LIMIT <= 67108863
21 LIMIT <= 2047 ║ 5 LIMIT <= 134217727
20 LIMIT <= 4095 ║ 4 LIMIT <= 268435455
19 LIMIT <= 8191 ║ 3 LIMIT <= 536870911
18 LIMIT <= 16383 ║ 2 LIMIT <= 1073741823
17 LIMIT <= 32767 ║ 1 LIMIT <= 2147483647
16 LIMIT <= 65535 ║ 0 if LIMIT <= 4294967295
在Arduino中,或使用GCC编译的任何C或C++代码,您可以使用
static inline int random_intrange(const int minval,
const int maxval)
{
if (maxval > minval) {
const unsigned int limit = maxval - minval;
const unsigned char shift = __builtin_clz(limit);
unsigned int u;
do {
u = random_unsigned_int() >> shift;
} while (u > limit);
return minval + u;
} else
return minval;
}
static inline unsigned int random_uintrange(const unsigned int minval,
const unsigned int maxval)
{
if (maxval > minval) {
const unsigned int limit = maxval - minval;
const unsigned char shift = __builtin_clz(limit);
unsigned int u;
do {
u = random_unsigned_int() >> shift;
} while (u > limit);
return minval + u;
} else
return minval;
}
只要random_unsigned_int()
是一个统一的伪随机数生成器,它返回unsigned int
s,从0
到UINT_MAX
,包括 。
- <random>在实践中应该实际使用哪个随机数引擎? std::mt19937?
- 是否可以为boost::random::uniform_int_distribution<>设置确定性种子?
- 'generate'不是窗口头文件中'std::random_device'的成员<random>
- 数组打印"random"值时出现问题
- 使用""的不可重现的随机数<random>
- <random> 尽管不是常量,但所有发行版都是线程安全的吗?
- 从时间生成'random'数字?
- 无法在 c++ 中包含"random"头文件
- Nemiver 找不到文件 /build/glibc-LK5gWL/glibc-2.23/stdlib/random.c
- 如何在 c++ 中正确读取 GRC 块"Random Source"的字节输出数据到自己的 OOT 块中?
- 如何从C++<random>获得一致的行为
- 为什么 random() 在窗口中不起作用
- 等效于C++中的numpy.random.choice函数
- Arduino 的新手。 "Random"值在复位时重复
- 在 c++ 中反转数组时,为什么在输入和输出之间得到一个"random"数字?
- 如何使用<random>填充标准::数组
- 标准::make_unique<T> vs 复位(新 T)
- stdlib.h's random() on MS Visual Studio 2008
- Boost::random::discrete_distribution构建后如何更改权重
- 使用 和 函数生成随机双向量<random>