【发布时间】:2013-04-25 20:55:21
【问题描述】:
讨论开始于my answer to another question。以下代码确定machine epsilon:
float compute_eps() {
float eps = 1.0f;
while (1.0f + eps != 1.0f)
eps /= 2.0f;
return eps;
}
在 cmets 中提出 1.0f + eps != 1.0f 测试可能会失败,因为 C++ 标准允许使用额外的精度。虽然我知道浮点运算实际上是以更高的精度执行的(比使用的实际类型指定的),但我碰巧不同意这个提议。
我怀疑在比较操作期间,例如== 或!=,操作数没有被截断到它们类型的精度。换句话说,1.0f + eps当然可以用比float更高的精度来求值(例如long double),结果会存放在可以容纳long double的寄存器中。但是,我认为在执行!= 操作之前,左操作数将从long double 截断为float,因此代码永远不会无法准确地确定eps(即它永远不会进行比预期更多的迭代)。
我在 C++ 标准中没有找到任何关于这种特殊情况的线索。此外,代码运行良好,而且我确信在其执行期间使用了额外精度技术,因为我毫不怀疑任何现代桌面实现实际上在计算期间使用额外精度。
你怎么看?
【问题讨论】:
-
在比较之前没有截断到类型的精度正是一些 GCC 用户在错误 323 的几个副本中抱怨的:gcc.gnu.org/bugzilla/show_bug.cgi?id=323(我不记得具体的错误报告,抱歉,错误 323 有点像包罗万象)。一个例子是
double d = 3. / 7.; if (d != 3. / 7.) /* taken */ … -
为什么不能直接使用
std::numeric_limits<T>::epsilon()? -
@masrtis:那是题外话。我可以,这里的重点不同。
-
我没找过(可能来自C标准),但我记得规则是浮点计算可以以更高的精度完成,而 将结果值存储 到适当类型的变量中会降低存储类型的精度。即便如此,一些编译器仍然保持更高的精度,除非您使用命令行选项表示尊重浮点存储的规则。无论哪种方式,比较都不是存储,因此可以以更高的精度计算比较的一方或双方。
标签: c++ floating-point comparison precision equality