【问题标题】:Can cout alter variables somehow?cout 可以以某种方式改变变量吗?
【发布时间】:2010-09-08 03:00:08
【问题描述】:

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

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

在某些时候,这个函数溢出并返回一个非常大的负值。为了尝试准确追踪发生这种情况的位置,我添加了一条 cout 语句,使函数看起来像这样:

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

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

(如果有帮助的话,float中存储的值只是一个整数值,并不是特别大。我只是将它放在float中以避免强制转换。)

【问题讨论】:

    标签: c++ floating-point cout cpu-registers floating-point-precision


    【解决方案1】:

    打印一个值到 cout 不应该以任何方式改变参数的值。

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

    加上cout语句,就是直接使用x的值了。没有它,优化器可能会删除变量,从而改变计算的顺序,从而改变答案。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

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

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

        【讨论】:

        • gcc.gnu.org/wiki/x87note 上也有一个 GCC 注释由于这种奇妙的行为,比较浮点计算也天生就被破坏了,除非使用预先计算的值。
        【解决方案4】:

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

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

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

        【讨论】:

          【解决方案5】:

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-07-21
            • 1970-01-01
            • 1970-01-01
            • 2021-07-24
            • 1970-01-01
            • 1970-01-01
            • 2015-07-05
            相关资源
            最近更新 更多