在我的数值模拟中,我有类似以下代码片段的代码
double x;
do {
x = /* some computation */;
} while (x <= 0.0);
/* some algorithm that requires x to be (precisely) larger than 0 */
在某些编译器(例如gcc)和平台(例如linux、x87数学)上,可能会以高于双精度的精度(“超额精度”)计算x
。(更新:这里所说的精度指的是精度和/或范围)。在这种情况下,即使下一次将x四舍五入为双精度后变成0,比较(x <= 0
)仍有可能返回false。(而且不能保证x不会在任意时刻被四舍五入。)
有没有一种方法可以执行此比较:
- 是可移植的,
- 适用于得到内联的代码,
- 没有性能影响,并且
- 不排除一些任意范围(0,eps)?
我尝试使用(x < std::numeric_limits<double>::denorm_min()
),但当使用SSE2数学时,这似乎会显着减慢循环。(我知道非规格化数可以减慢计算,但我没想到它们在移动和比较时会更慢。)
更新:
一种替代方案是使用volatile
强制将x
写入内存,然后进行比较,例如:
} while (*((volatile double*)&x) <= 0.0);
然而,根据应用程序和编译器所应用的优化方式,这种解决方案可能会引入明显的开销。
更新: 任何公差问题的问题在于它非常主观,即它取决于特定的应用程序或上下文。我更倾向于在没有过度精度的情况下进行比较,这样我就不必做出任何额外的假设或将一些任意的 epsilon 引入到我的库函数的文档中。
((double)x) <= 0.0
,会发生什么? - Christoph