Arduino基于二进制的随机数生成函数异常行为解析
Arduino随机数生成异常原因解析:pow()浮点精度与random()范围问题
核心问题1:pow()函数的浮点精度损失
pow()是浮点运算函数,计算整数幂时,受二进制浮点数精度限制,可能出现结果略小于理论整数值的情况。例如:
- 计算
pow(2, 2)时,实际得到的可能不是精确的4.0,而是3.9999999999 - 当这个浮点值被强制转换为
int类型时,会直接截断小数部分,得到3而非预期的4
对应到你的代码场景:
- 当
bitnum=3时,mini = pow(2, 2)本应得到4,实际却变成了3 - 此时
random(3, 8)生成3~7之间的数,其中3(二进制11)是2位二进制数,就出现了你遇到的异常 - 同理,
bitnum=4时pow(2,3)可能得到7.999999,转成int是7,random(7,16)会生成7(二进制111)这种3位二进制数;bitnum=5时会生成15(二进制1111)这种4位二进制数
核心问题2:Arduino random()函数的范围规则
Arduino的random(min, max)生成左闭右开区间的随机数:
- 生成的数包含
min,但不包含max - 你的需求是生成
[2^(bitnum-1), 2^bitnum -1]的数,正好对应random(2^(bitnum-1), 2^bitnum)的输出范围(因为2^bitnum不被包含,所以最大数是2^bitnum -1)
为什么修改mini = pow(...) +1能解决问题?
当pow()的结果被截断为2^(bitnum-1)-1时,加1之后正好修正为预期的2^(bitnum-1),此时random(mini, MAX)的范围回到正确区间,不会再生成bitnum-1位的二进制数。
更可靠的解决方案:用位运算替代pow()
浮点运算不仅有精度问题,效率也不如整数位运算。对于2的整数次幂,直接用**左移运算符<<**计算,完全没有精度损失:
2^n等价于1 << n2^(bitnum-1)等价于1 << (bitnum-1)
同时注意:randomSeed(millis())只需要初始化一次,放在函数里每次调用都会重置随机种子,导致随机数序列重复或不够随机,应该只执行一次。
优化后的代码:
int DecimalNum(int bitnum) { static bool isSeeded = false; if (!isSeeded) { randomSeed(millis()); isSeeded = true; } int mini = 1 << (bitnum - 1); int MAX = 1 << bitnum; return random(mini, MAX); }
内容的提问来源于stack exchange,提问作者石佳恩
相关产品推荐
相关产品推荐

