开门见山,直接上代码:
std::wstring arithmetic_expression::natrual_number_or_fraction_generator()
{
static std::default_random_engine e;
static std::uniform_int_distribution<unsigned> natural_fraction(0, 1);
static std::uniform_int_distribution<unsigned> natural(1, number_range - 1);
std::wstring result;
if (natural_fraction(e) == 0)
{
result = MyFraction(natural(e), 1).to_wstring();
}
else if (natural_fraction(e) == 1)
{
unsigned a = natural(e);
unsigned b = natural(e);
result = MyFraction(a, b).to_wstring();
}
return result;
}
上述函数源自于一个生成四则运算的小程序,其功能是在产生四则运算的数字时,随机的产生自然数 或者真分数 ,但在测试时出现了奇怪的输出:
可以看到在箭头位置部分的数值没有正确的生成。
为了解决这个问题,我将代码改成了如下的形式,增加一个中间变量储存随机数生成器的值。
std::wstring arithmetic_expression::natrual_number_or_fraction_generator()
{
static std::default_random_engine e;
static std::uniform_int_distribution<unsigned> natural_fraction(0, 1);
static std::uniform_int_distribution<unsigned> natural(1, number_range - 1);
std::wstring result;
unsigned choice = natural_fraction(e);
if (choice == 0) //改变
{
result = MyFraction(natural(e), 1).to_wstring();
}
else if (choice == 1)
{
unsigned a = natural(e);
unsigned b = natural(e);
result = MyFraction(a, b).to_wstring();
}
return result;
}
经过修改后可以正常的生成表达式了,问题得到了解决,但原因是什么呢?思考了一中午后,终于发现了关键所在:
-
每次调用随机数分布函数 时,都会生成一个新的随机数,这是它的语法特征;
-
我建立的0-1分布,只有两种结果,0 或者1;
-
在第一种写法中,
if...else
判断中的条件语句每次都调用了随机数分布函数,那么可能存在如下的情况- 在
if (natural_fraction(e) == 0)
时,natural_fraction(e)
的值为1,由于条件判断为假,跳到else if
; - 此时,继续调用
natural_fraction(e)
,于是生成了新的随机数, 其值可能为0,这样的话else if (natural_fraction(e) == 1)
也为假,奇怪现象就此产生 ,返回值变成了空值。
事实是否就是这样的呢?在debug模式下观察出错的调用部分:
- 在
可以看到,与先前推断的一致。至此,终于揭开了这个bug的背后原因,同时也暴露了我对随机数使用的经验缺乏,掉进了这么个坑里。
特此记录!