2013-04-05 65 views
0

我知道双打只是近似值。不过,我很惊讶,C++ double division并返回

double f(int x, int y) 
{ 
    return double(x)/y; 
} 

double f(int x, int y) 
{ 
    double z = double(x)/y; 
    return z; 
} 

可以返回不同的值。有谁知道为什么?

+9

您是否有这样的例子? – 2013-04-05 12:54:51

+1

发布完整的测试用例,并描述您的问题。 – LihO 2013-04-05 12:55:57

+3

[我已经帮你发布了一个显示的例子](http://liveworkspace.org/code/4igUk5$1)这个问题。 – 2013-04-05 12:58:42

回答

0

我认为这种情况发生的唯一方法是在x87 FPU上优化编译器。 x87 FPU使用长双精度,因此寄存器中的值可以比堆栈中双变量中的值更精确地保存。至少可以想象,给定上述代码的optmising编译器可能会在一种情况下使用寄存器来返回值,另一种情况则使用堆栈。

但我希望看到一个真实的例子。

+0

这几乎可以肯定是x87 FPU的一个例子。并不是编译器在浮点寄存器中返回一个,另一个在实际的“double”中;它是编译器强制执行的规则,即返回值必须是变量中的值(已被舍入为“double”),或者读取它刚写入的内容以返回它,或者明确强制舍入FPU中的值。 – 2013-04-05 13:54:43

0

我写了方法,我做了一个简单的测试,调用了它们两个。 这些值简单[按预期]相等。 这里有两个选项: 1)你在提出一个错误的问题。 [我不这么认为!] 2)当你将值存储在z中时,编译器会进行更多的隐式转换,从而降低变量的精度。 问题可能也是您传递价值的方式。事实上,在很多语言中,如果你得到.5 [E.G. float = .5],则更精确的是进行分割[E.G. float z = 1/2;]

4

“为什么”的主要原因是标准允许它(除了 ,我不是100%肯定它会这么做)。实际的原因是 在某些处理器(包括英特尔32位处理器), 浮点寄存器比double更精确。 中间体计算在寄存器完成的,如果它们符合 (和标准明确允许中间结果有 更精确),所以任何给定表达式的结果将 取决于编译器如何管理其寄存器,并且当它 外溢到记忆。许多(大多数?)编译器用于这样的处理器将返回浮点值在一个寄存器, ,他们保持额外的精度。 (我不确定这是否是合法的 。当分配一个double时,我认为当复制 构造一个double时,必须使该值合适。返回 值是复制构造,所以我认为它应该强制 双适应。不管......大多数编译器不会让你有 处理它,不管什么样的标准可能会或可能 不必说了。)

我认为你可以阻止这种通过明确铸造最终 的结果,即:

return double(double(x)/y); 

,但我不确定(既不是标准所说的关于 的标准,也不是关于编译器的实际做法)。

请注意,无论结果是否有差异,取决于您对它们所做的操作有多少取决于 。如果您立即将 分配给double,或者将它们传递给另一个功能,那么 需要double,那么发生的一切就是舍入 稍后发生(但仍保持相同的值)。但是,如果您在表达式中使用 的值,则所有投注都将关闭。在 的情况下,2.0 * f(a, b)可能会导致不同的值 ,具体取决于您对f的实施,即使在舍入后也是如此。 而最明显的是,f(a, b) == f(a, b)可能会返回false。 (我在哪里见过这引起了std::sort崩溃的情况下使用的 比较功能确实沿 return lhs.f() < rhs.f();线的东西,并返回truelhsrhs是同一个对象的引用;编译器溢出的结果的第一个函数调用内存,然后与第二个函数返回的寄存器中的值进行比较)。