无符号long * double乘法中的奇怪错误

时间:2016-07-08 12:56:05

标签: c++ debugging type-conversion

我对我的程序中发生的错误完全感到困惑,这里是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,因为popvector<>),否则用作索引的结果完全是胡说八道并导致段违规。所有其他值都表现得非常好,对数保证在0-1之间。然而-500次它突然出现了几个负面因素?!

更奇怪的是,我无法隔离MWE。 500*log(whatever)(size_t)500*log(whatever)(float)500*log(whatever)等语句都会按预期返回相同的内容。

有什么想法在这里发生了什么?

编辑:accepted answer之后,第85行-sz在乘法之前执行,并且因为sz未被强制转换为浮点数,这导致ULONG_MAX附近的某些结果。我仍然会说这是出乎意料的行为,因为数学上的乘法应该先发生......

1 个答案:

答案 0 :(得分:1)

在乘法之前执行否定。 因此,-sz对无符号数 sz执行否定,这会产生一个非常大的数字(无符号数不能变为负数)。

如果您想了解其工作原理,请查看维基百科上的two's complement页面。

由于log(1 - x + x * exp(-1))是负浮点数,因此最终结果是一个非常大的负浮点数。

相关问题