下溢和浮点数算术检查

3
我正在编写一个涉及多个长数学公式的程序库,有时在使用双精度浮点数时会出现下溢情况。其中一个例子如下所示:

(Exp(-a*a) - Exp(-b*b))*Exp(c)*Exp(d) 

而且a、b、c、d也涉及到一些类似的计算。如果我没有检测到下溢(例如指数之差),会导致我无法承受的行为。 (当这种差异剪辑为零时,绝对误差和相对误差都可能非常大,而其他指数非常大)。
是否有类似于“checked”关键字适用于双精度浮点数的东西?是否有某种方法可以辅助实现检查?
任何确保正确性的解决方案,即使引发比必要更多的问题,对我来说都是好的。
此问题被建议作为重复问题(此链接),但是对于我来说,“在每次乘法之前手动检查”不是特别有用的解决方案。

可能是如何检测Double类型的完全精度丢失?的重复问题。 - O. Jones
@O.Jones 在某种意义上是重复的,但那里没有给出真正的解决方案。在非程序生成代码之前逐个检查每个乘法是可行的,但出于明显的原因,我宁愿避免这样做。 - Radost
1
C#不会为浮点下溢抛出异常,而是将结果设置为零。因此,您必须自己进行epsilon处理。这真是让人头疼,正如您所发现的那样。 - O. Jones
如果性能和开发时间不是问题,您可以定义自己的类,其中包含一个浮点数,并重载运算符*和其他操作(通过执行检查)。这样,您的代码将与以前一样清晰,但需要一些工作。 - user2956272
1个回答

3
是否有类似于checked关键字适用于双精度浮点数的功能?
没有。
我能以某种辅助方式实现检查吗?
一个不好的解决方案:根据您使用的硬件,浮点运算芯片可能会设置一个指示操作是否下溢的标志。我不建议调用非托管代码来读取浮点芯片上的那个标志。(我在最初的Microsoft版本Javascript中编写了这段代码,而且很难得到正确的逻辑。)
一个更好的解决方案:您可以考虑编写一个符号逻辑库。例如,如果您制作自己的数字类型,会发生什么情况?
struct ExpNumber 
{
  public double Exponent { get; }
  public ExpNumber(double e) => Exponent = e;
  public static ExpNumber operator *(ExpNumber x1, ExpNumber x2) => 
    new ExpNumber(x1.Exponent + x2.Exponent);

等等。你可以使用你已知的幂次方公式自定义加法、减法、乘方、对数等运算。当需要将这些计算结果转换为double类型时,你可以使用任何稳定的算法,避免下溢。

问题在于,double类型有意降低了表示能力和精度,以换取极大的速度提升。如果你需要精确表示小于10e-200的数字,那么double并不适合你;它们是为解决物理计算问题而设计的,而不存在如此小的物理量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接