将float输入到字符串流时的“浮点无效操作”

时间:2012-05-09 11:20:07

标签: c++ floating-point-exceptions

我有一段简单的代码从FORTRAN生成的REAL数组中提取浮点数,然后将其插入到流中以进行日志记录。虽然这适用于前30个案例,但是在31日它崩溃了一个"浮点无效操作"。

代码是:

int FunctionDeclaration(float* mrSwap)
{
...
float swap_float;
stringstream message_stream;
...
swap_float = *(mrSwap+30-1);
...
message_stream.clear();
message_stream <<  30 << "\t" << swap_float << "\tblah blah blah \t";

调试时,崩溃前的实例(上面的最后一行)上的swap_float值为1711696.3 - 除此之外,这个值远远大于此时的大多数值,没有什么特别之处。

我也尝试用cerr替换message_stream,并遇到了同样的问题。到目前为止,我认为cerr几乎是无法构造的 - 一个简单的浮子如何破坏它呢?

修改

感谢您的评论:我已经添加了mrSwap的声明。 mrSwap大约200个长,所以我还有很长的路要走。它是在我的控件之外填充的,并且个别条目可能不会被填充 - 但据我所知,这只是意味着swap_float将被设置为随机浮点数?

2 个答案:

答案 0 :(得分:1)

  

个人参赛作品可能不会被填充 - 但最好是我的   理解,这只是意味着swap_float将被设置为a   随机漂浮?

着重没有。 IEEE浮点数中的某些位模式表示无效数字 - 例如,溢出算术运算的结果,或无效的运算结果(例如0.0 / 0.0)。令人费解的是,调试器显然接受该号码是有效的,而cout则没有。

尝试获取swap_float的位布局。在32位系统上:

int i = *(int*)&swap_float;

然后以十六进制打印i,让我们知道你看到了什么。

已更新以添加:来自Mike的评论,i = 1238430338,其为十六进制的49D0F282。这是一个有效的浮点数,恰好等于1711696.25。所以我不知道发生了什么,我很害怕。我唯一可以建议的是,编译器可能直接从mrSwap数组加载无效的浮点数到浮点寄存器库,而不经过swapFloat。因此swapFloat的真正价值根本不适用于调试器。要检查这一点,请尝试

int j = *(int*)(mrSwap+30-1);

告诉我们你的看法。

再次更新以添加:另一种可能性是延迟浮点陷阱。浮点协处理器(这些天内置在CPU中)由于某些非法操作而产生浮点中断,但在 next 浮点运算之前,中断不会被注意到尝试。所以这次崩溃可能是之前的浮点运算的结果,它可能在任何地方。祝你好运...

答案 1 :(得分:1)

我只是添加这个答案以突出TonyK上面的答案中的正确解决方案 - 因为我们做了一些循环,答案已被编辑,并且由于评论中有几个突出点,实际答案可能不会立即明显。所有的功劳都归功于TonyK的解决方案。

“另一种可能是延迟浮点陷阱。浮点协处理器(这些天内置在CPU中)由于某些非法操作而产生浮点中断,但中断不会在尝试下一个浮点操作之前会注意到。所以这次崩溃可能是之前浮动操作的结果,可能是任何地方。“ - TonyK

这确实是问题所在:在我使用IsSame进行比较时,另一个值是NaN(在此上下文中这是一个有效值),虽然它很乐意从swap_float中减去它,但它在说下一个报告下一个操作为错误。我不得不说我完全没有意识到这是可能的 - 我认为如果它奏效了,那就有用了。