如何处理浮点计算中的过度精度?

Ste*_*han 9 c c++ floating-point

在我的数值模拟中,我的代码类似于以下代码段

double x;
do {
  x = /* some computation */;
} while (x <= 0.0);
/* some algorithm that requires x to be (precisely) larger than 0 */
Run Code Online (Sandbox Code Playgroud)

对于某些平台上的某些编译器(例如gcc)(例如linux,x87 math),有可能x以高于双精度("具有过度精度")的方式计算.(更新:当我在这里谈到精度时,我的意思是精度/和/范围.)在这种情况下,可以想象,x <= 0即使下一次x向下舍入到双精度,它也会变为0,而compare()返回false.(和无法保证x不会在任意时间点向下舍入.)

有没有办法进行这种比较

  • 便携,
  • 适用于内联的代码,
  • 没有性能影响
  • 不排除某些任意范围(0,eps)?

我尝试使用(x < std::numeric_limits<double>::denorm_min())但是在使用SSE2数学时,这似乎显着减慢了循环.(我知道非正规可以减慢计算速度,但我没想到它们只是移动并比较慢.)

更新: 另一种方法是在比较之前使用volatile强制x进入内存,例如通过写入

} while (*((volatile double*)&x) <= 0.0);
Run Code Online (Sandbox Code Playgroud)

但是,根据应用程序和编译器应用的优化,此解决方案也会引入明显的开销.

更新: 任何容忍的问题是它是非常随意的,即它取决于具体的应用程序或上下文.我更愿意在没有过多精度的情况下进行比较,这样我就不必做任何额外的假设或在我的库函数的文档中引入一些任意的epsilons.

Chr*_*oph 7

正如Arkadiy在评论中指出的那样,一个明确的演员((double)x) <= 0.0 应该有效 - 至少根据标准.

C99:TC3,5.2.4.2.2§8:

除了赋值和强制转换(删除所有额外的范围和精度)之外,具有浮动操作数的操作值和受常规算术转换和浮动常量限制的值将被评估为其范围和精度可能大于类型.[...]


如果在x86上使用GCC,则可以使用标志-mpc32,-mpc64并将-mpc80浮点运算的精度设置为单精度,双精度和双精度.


Joh*_*ook 1

我想知道你是否有正确的停止标准。听起来 x <= 0 是一个异常条件,但不是终止条件,并且终止条件更容易满足。也许 while 循环内应该有一个break语句,当满足某些容差时停止迭代。例如,当两个连续迭代彼此足够接近时,许多算法就会终止。