处理.NET中的浮点错误

Han*_*ank 8 .net floating-point numerical

我正在C#/ .NET中开展科学计算和可视化项目,我们使用doubles来表示所有物理量.由于浮点数总是包含一些舍入,我们有简单的方法来进行相等比较,例如:

static double EPSILON = 1e-6;

bool ApproxEquals(double d1, double d2) {
    return Math.Abs(d1 - d2) < EPSILON;
}
Run Code Online (Sandbox Code Playgroud)

很标准.

然而,EPSILON当我们遇到"相等"数量的误差大于我们预期的情况时,我们不断发现自己必须调整幅度.例如,如果将5个大doubles 相乘然后除以5次,则会失去很多精度.它已经达到了我们无法使EPSILON过大的程度,否则它会给我们带来误报,但我们仍然会得到假阴性.

一般来说,我们的方法是寻找更多数值稳定的算法来使用,但程序是非常计算的,而且我们已经能够做到这一点.

有没有人有任何好的策略来处理这个问题?我Decimal稍微调查了这个类型,但我对性能感到担心,我对它的了解并不知道它是否可以解决问题或者只是模糊它.Decimal如果它能解决这些问题,我愿意接受一个适度的性能命中(比方说,2x),但性能肯定是一个问题,因为代码主要受到浮点运算的限制,我不认为它是一个无理的担忧.我看到人们引用了100倍的差异,这肯定是不可接受的.

此外,切换到Decimal其他复杂情况,例如Math库中普遍缺乏支持,因此我们必须编写自己的平方根函数,例如.

有什么建议?

编辑:顺便说一句,我使用常数epsilon(而不是相对比较)的事实不是我的问题.我只是把它作为一个例子,它实际上不是我的代码的snippit.改变相对比较不会对问题产生影响,因为问题是由于数字变得非常大而后来又变小而失去精确度.例如,我可能有一个值1000,然后我对它进行一系列计算,这将导致完全相同的数字,但由于精度损失,我实际上有1001.如果我然后去比较这些数字,它不会如果我使用相对或绝对比较(只要我以对问题和规模有意义的方式定义比较),那就更重要了.

无论如何,正如Mitch Wheat建议的那样,算法的重新排序确实有助于解决这些问题.

Mit*_*eat 5

这不是.NET独有的问题.降低精度损失的策略是重新排序计算,以便将大量乘以小数量并加/减相似大小的数量(显然不会改变计算的性质).

在您的示例中,不是将5个大数量相乘,然后除以5个大数量,而是重新排序以将每个大数量除以其中一个除数,然后将这5个部分结果相乘.

出于兴趣?(如果你还没有读过):每个计算机科学家应该知道浮点运算