cout 可以以某种方式改变变量吗?

Can cout alter variables somehow?

提问人:Jason Baker 提问时间:9/8/2008 最后编辑:mskfisherJason Baker 更新时间:5/9/2012 访问量:2431

问:

所以我有一个函数,看起来像这样:

float function(){
    float x = SomeValue;
    return x / SomeOtherValue;
}

在某些时候,此函数会溢出并返回一个非常大的负值。为了尝试准确追踪发生这种情况的位置,我添加了一个 cout 语句,使该函数如下所示:

float function(){
    float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

它奏效了!当然,我通过使用双精度完全解决了这个问题。但我很好奇为什么当我打开它时该功能可以正常工作。这是典型的,还是我遗漏了其他地方的错误?

(如果有什么帮助,存储在浮点数中的值只是一个整数值,而不是一个特别大的值。我只是把它放在一个浮子里以避免铸造。

C++ cout cpu-registers 浮点精度

评论


答:

3赞 David Dibben 9/8/2008 #1

将值打印到 cout 不应以任何方式更改参数的值。

但是,我看到了类似的行为,添加调试语句会导致值发生变化。在这些情况下,可能还有这个,我的猜测是额外的语句导致编译器的优化器行为不同,因此为您的函数生成不同的代码。

添加 cout 语句意味着直接使用 x 的 vaue。没有它,优化器可以删除变量,从而改变计算的顺序,从而改变答案。

0赞 John Boker 9/8/2008 #2

我不认为 cout 对变量有任何影响,问题必须在其他地方。

18赞 Rob Walker 9/8/2008 #3

欢迎来到浮点的美妙世界。你得到的答案可能取决于你编译代码时使用的浮点模型。

发生这种情况的原因是 IEEE 规范与运行代码的硬件之间存在差异。您的 CPU 可能具有 80 位浮点寄存器,用于保存 32 位浮点值。这意味着,当值保留在寄存器中时,精度要比强制到内存地址时(也称为“归位”寄存器)要高得多。

当您将值传递给 cout 时,编译器必须将浮点写入内存,这会导致精度损失和有趣的行为 WRT 溢出情况。

请参阅有关 VC++ 浮点交换机的 MSDN 文档。您可以尝试使用 /fp:strict 进行编译,看看会发生什么。

评论

0赞 hazzen 9/9/2008
在 gcc.gnu.org/wiki/x87note 上也有一个 GCC 注释 由于这种奇妙的行为,除非使用预先计算的值,否则比较浮点计算本质上也是失败的。
2赞 David Joyner 9/9/2008 #4

顺便说一句,使用以下命令声明不可变变量总是一个好主意:const

float function(){
    const float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

除其他事项外,这将防止您无意中将变量传递给可能通过非引用修改它们的函数。const

1赞 Joe 8/31/2010 #5

cout 会导致对变量的引用,这通常会导致编译器强制将其溢出到堆栈中。

因为它是一个浮点数,这可能会导致它的值从它通常具有的双精度或长双精度表示中被截断。

调用任何采用指针或对 x 的引用的函数(非内联)最终都会导致相同的行为,但如果编译器后来变得更聪明并学会内联它,你同样会被搞砸:)