【问题标题】:Under flow with floating point arithmetic checking带有浮点算术检查的流下
【发布时间】:2019-06-24 22:23:52
【问题描述】:

我正在编写一个包含多个长数学公式实例的库,在使用双精度时有时会下溢。一个例子可能是:

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

而且 a,b,c,d 也涉及一些类似类型的计算。 我可以处理双打出错(并返回适当的错误消息或一些分析界限),但如果我没有检测到下溢(例如指数的差异),它会导致我无法承受的行为。 (当这个差值归零而其他指数非常大时,绝对误差和相对误差都可能很大)。

是否有类似于 checked 关键字的东西适用于双打? 有什么方法可以帮助我实施检查吗?

任何确保其正确性的解决方案,即使是引发比必要更多的标志的解决方案对我都有好处。


This question 被建议为重复但“在每次乘法之前手动检查”对我来说并不是一个特别有用的解决方案。

【问题讨论】:

  • @O.Jones 在某种意义上重复,但没有给出真正的解决方案。使用非程序生成的代码检查每个乘法是可行的,但出于明显的原因,我宁愿避免这样做。
  • C# 不会为浮动下溢抛出异常。它只是将结果设置为零。所以你坚持做你自己的 epsilon 工作。这是颈部疼痛。正如你所发现的那样。
  • 如果性能和开发时间不是问题,您可以定义自己的类,其中包含浮点和重载运算符 * 以及其他操作(通过执行检查)。这样你的代码会像以前一样干净,但需要一些工作。

标签: c# underflow


【解决方案1】:

有没有类似于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);

等等。您可以使用您知道的幂等式定义自己的加法、减法、幂、对数等。然后,当需要将事情变回双倍时,您可以使用任何您喜欢的避免下溢的稳定算法来实现它。

问题在于,双打故意以降低表示能力和准确性来换取速度的大幅提高。如果您需要准确表示小于 10e-200 的数字,双精度数不适合您;它们旨在解决物理计算中的问题,没有那么小的物理量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    相关资源
    最近更新 更多