繁体   English   中英

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

[英]How to deal with excess precision in floating-point computations?

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

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

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

有没有办法进行这种比较

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

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

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

} while (*((volatile double*)&x) <= 0.0);

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

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

正如Arkadiy在评论中所说,显式演员((double)x) <= 0.0 应该有效 - 至少根据标准。

C99:TC3,5.2.4.2.2§8:

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


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

在你的问题中,你说过使用volatile会起作用,但是会有很大的性能损失。 如何在比较期间使用volatile变量,允许x保存在寄存器中?

double x; /* might have excess precision */
volatile double x_dbl; /* guaranteed to be double precision */
do {
  x = /* some computation */;
  x_dbl = x;
} while (x_dbl <= 0.0);

您还应该检查是否可以通过明确使用long double来加速与最小次正规值的比较并缓存此值,即

const long double dbl_denorm_min = static_cast<long double>(std::numeric_limits<double>::denorm_min());

然后比较

x < dbl_denorm_min

我假设一个体面的编译器会自动执行此操作,但是人们永远不会知道......

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

好吧,GCC有一个标志,-fexcess-precision会导致你正在讨论的问题。 它还有一个标志,-ffloat-store,它解决了你正在讨论的问题。

“不要将浮点变量存储在寄存器中。这样可以避免在机器上出现不必要的过高精度,例如68000浮动寄存器(68881)保持精度高于双倍应该具有的精度。”

我怀疑该解决方案没有性能影响,但影响可能不会过于昂贵。 随机谷歌搜索表明它的成本约为20%。 其实,我不认为这一个解决方案,它是便携式和对性能没有影响,因为迫使芯片不使用过多的精度往往要涉及到一些非自由操作。 但是,这可能是您想要的解决方案。

一定要检查绝对值。 它需要是一个大约零,上下的epsilon。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM