2

我知道双打只是近似值。但我很惊讶

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

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

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

4

3 回答 3

6

“为什么”的主要原因是标准允许它(除了我不是 100% 肯定它这样做)。务实的原因是在某些处理器(包括 Intel 32 位处理器)上,浮点寄存器的精度高于double. 中间计算是在寄存器中完成的,如果它们适合(并且标准明确允许中间结果具有更高的精度),因此任何给定表达式的结果将取决于编译器如何管理其寄存器以及何时溢出到内存。许多(大多数?)此类处理器的编译器将在寄存器中返回浮点值,以保持额外的精度。(我不确定这是否合法。在分配双精度时,我认为在复制构造双精度时,必须使值适合。返回值是复制构造,所以我认为它应该强制双精度. 无论如何...大多数编译器都没有,所以你必须处理它,不管标准可能会或可能不会对它说什么。)

我认为您可以通过显式转换最终结果来防止这种情况,即:

return double( double(x)/y );

,但我不确定(既不知道标准对它的描述,也不知道编译器实际做了什么)。

请注意,结果是否不同在某种程度上取决于您对它们的处理方式。如果您立即将它们分配给 a double,或者将它们传递给另一个需要 a 的函数double,那么所发生的只是舍入稍晚(但仍然在相同的值上)。但是,如果您在表达式中使用该值,则所有赌注都将被取消。在您的情况下,即使在舍入之后,2.0 * f( a, b )也可能会根据您的实现产生不同的值。f最明显的是,f( a, b ) == f( a, b )可能返回 false。(我见过一个导致std::sort崩溃的情况。使用的比较函数做了一些类似的事情 ,return lhs.f() < rhs.f();并且在true何时返回lhsrhs是对同一个对象的引用;编译器将它调用的第一个函数的结果溢出到内存中,然后与第二个函数返回的寄存器中的值进行比较。)

于 2013-04-05T13:26:39.350 回答
2

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

但我想看一个真实的例子。

于 2013-04-05T13:01:02.137 回答
0

我编写了方法,并做了一个简单的测试,同时调用了它们。这些值只是[作为方面]相等。这里有两个选择:1)你提出了一个错误的问题。[我不这么认为!] 2) 当您将值“存储”在 z 中时,编译器会进行更多隐式转换,从而降低变量的精度。问题也可能是您传递值的方式。事实上,在许多语言中,如果通过赋值得到[EG float = .5],那么进行除法 [EG ].5会更精确float z = 1 / 2;

于 2013-04-05T13:15:00.977 回答