据我所知,双打只是近似值。但我很惊讶
double f(int x, int y)
{
return double(x)/y;
}
和
double f(int x, int y)
{
double z = double(x)/y;
return z;
}
可以返回不同的值。有谁知道为什么?
答案 0 :(得分:6)
“为什么”的主要原因是标准允许它(除了
我不是100%确定它确实如此)。务实的原因是
在某些处理器(包括Intel 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();
,并在true
时返回lhs
和rhs
是对同一个对象的引用;编译器将它调用的第一个函数的结果溢出到内存中,然后与第二个函数返回的寄存器中的值进行比较。)
答案 1 :(得分:1)
我能想到的唯一方法就是在x87 FPU上使用优化编译器。 x87 FPU使用长双精度,因此寄存器中的值可以比堆栈中的双变量中的值更精确地保持。至少可以想象,给定上述代码的优化编译器可能在一种情况下使用寄存器作为返回值,而在另一种情况下使用堆栈。
但我希望看到一个真实的例子。
答案 2 :(得分:0)
我写了这些方法,我做了一个简单的测试,调用它们。
这些值只是[视为]相等。
这有两个选择:
1)你提出了一个虚假的问题。 [我不这么认为!]
2)当您将值“存储”在z中时,编译器会进行更多隐式转换,从而降低变量的精度。
问题也可能是您传递值的方式。
事实上,在许多语言中,如果你得到.5
[E.G. float = .5]通过赋值,进行划分会更精确[E.G. float z = 1 / 2;
]