我正在使用 C#/.NET 进行科学计算和可视化项目,我们使用double
s 来表示所有物理量。由于浮点数总是包含一些舍入,我们有简单的方法来进行相等比较,例如:
static double EPSILON = 1e-6;
bool ApproxEquals(double d1, double d2) {
return Math.Abs(d1 - d2) < EPSILON;
}
很标准。
EPSILON
然而,当我们遇到“相等”量的误差大于我们预期的情况时,我们经常发现自己不得不调整量级。例如,如果将 5 个大double
s 相乘,然后再除以 5 次,就会损失很多准确度。它已经到了我们不能让 EPSILON 变得更大的地步,否则它会给我们带来误报,但我们仍然会得到误报。
一般来说,我们的方法是寻找更多数值稳定的算法来使用,但该程序的计算量很大,我们能做的只有这么多。
有没有人有任何好的策略来处理这个问题?我对这种Decimal
类型进行了一些研究,但我担心性能,而且我对它的了解还不够,不知道它是否会解决问题或只会掩盖问题。如果它可以解决这些问题,我愿意接受适度的性能损失(比如 2 倍)Decimal
,但性能绝对是一个问题,并且由于代码主要受浮点运算的限制,我不认为这是一个不合理的担忧。我见过有人引用 100 倍的差异,这绝对是不可接受的。
此外,切换到Decimal
还有其他复杂性,例如库中普遍缺乏支持Math
,因此我们必须编写自己的平方根函数,例如。
有什么建议吗?
编辑:顺便说一句,我使用常量 epsilon(而不是相对比较)这一事实不是我的问题的重点。我只是把它放在那里作为一个例子,它实际上并不是我的代码片段。更改为相对比较不会对问题产生影响,因为当数字变得非常大然后又变小时,问题就会出现精度下降。例如,我可能有一个值 1000,然后我对其进行一系列计算,结果应该完全相同,但由于精度损失,我实际上有 1001。如果我再去比较这些数字,它不会如果我使用相对或绝对比较并不重要(只要我以对问题和规模有意义的方式定义了比较)。
无论如何,正如 Mitch Wheat 建议的那样,算法的重新排序确实有助于解决问题。