我对我的程序中发生的错误完全感到困惑,这里是gdb
会话的摘录,其中包含相关的代码(空行和遗漏):
(gdb) list
81 Candidate& rankSelect() {
82 float x = (std::uniform_real_distribution<float>(0, 1))(Context::rng);
83 /*debug*/ auto sz = pop.size();
84 /*debug*/ float a = -(float)sz*log(1 - x + x*exp(-1));
85 /*debug*/ float b = -sz*log(1 - x + x*exp(-1));
86 return pop[-(float)pop.size()*log(1 - x + x*exp(-1))];
87 }
88
...
(gdb) frame
...
86 return pop[-(float)pop.size()*log(1 - x + x*exp(-1))];
(gdb) print sz
$1 = 500
(gdb) ptype sz
type = unsigned long
(gdb) print a
$2 = 54,559597
(gdb) print b
$3 = -2,0128938e+18
可以看出,我必须添加pop.size()
的显式转换,这只是一个小整数(类型size_type
又名unsigned long
,因为pop
是vector<>
),否则用作索引的结果完全是胡说八道并导致段违规。所有其他值都表现得非常好,对数保证在0
和-1
之间。然而-500
次它突然出现了几个负面因素?!
更奇怪的是,我无法隔离MWE。 500*log(whatever)
,(size_t)500*log(whatever)
,(float)500*log(whatever)
等语句都会按预期返回相同的内容。
有什么想法在这里发生了什么?
编辑:在accepted answer之后,第85行-sz
在乘法之前执行,并且因为sz
未被强制转换为浮点数,这导致ULONG_MAX
附近的某些结果。我仍然会说这是出乎意料的行为,因为数学上的乘法应该先发生......
答案 0 :(得分:1)
在乘法之前执行否定。 因此,-sz对无符号数 sz执行否定,这会产生一个非常大的数字(无符号数不能变为负数)。
如果您想了解其工作原理,请查看维基百科上的two's complement页面。
由于log(1 - x + x * exp(-1))是负浮点数,因此最终结果是一个非常大的负浮点数。