C ++双重除法和返回

use*_*284 1 c++ floating-point

我了解双打只是近似值。但是我很惊讶

double f(int x, int y)
{
    return double(x)/y;
}
Run Code Online (Sandbox Code Playgroud)

double f(int x, int y)
{
    double z = double(x)/y;
    return z;
}
Run Code Online (Sandbox Code Playgroud)

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

Jam*_*nze 6

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

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

return double( double(x)/y );
Run Code Online (Sandbox Code Playgroud)

,但我不确定(既不知道该标准怎么说,也不知道编译器实际做什么)。

请注意,结果是否不同取决于您对它们的处理方式。如果立即将它们分配给double,或将它们传递给需要的另一个函数double,则所有发生的结果是舍入稍晚一些(但仍使用相同的值)。但是,如果您在表达式中使用该值,则所有选择均无效。就您而言,即使舍入后,2.0 * f( a, b )根据您的实现可能会产生不同的值f。并且最明显的是,f( a, b ) == f( a, b )可能返回false。(我在哪里见过这引起了的情况下std::sort崩溃。所使用的比较函数做线沿线的东西 return lhs.f() < rhs.f();,并在返回truelhsrhs是对同一对象的引用;编译器会将调用的第一个函数的结果溢出到内存中,然后与第二个函数返回的寄存器中的值进行比较。)