Dealing with floating point errors in .NET

纵然是瞬间 提交于 2019-11-29 06:50:44

This is not a problem unique to .NET. The strategy to reduce loss of precision is to re-order calculations so that you multiply large quantities times small quantities and add/subtract similiar sized quantities (without changing the nature of the calculation, obviously).

In your example, rather than multiply 5 large quantities together and then divide by 5 large quantities, re-order to divide each large quantity by one of the divisors, and then multiply these 5 partial results.

Of interest? (if you haven't already read): What Every Computer Scientist Should Know About Floating-Point Arithmetic

Your best answer is always better algorithms, of course. But it seems to me that if your values aren't all within a couple of orders of magnitude of 1, the using a fixed epsilon is not a good strategy. What you want to do instead is to insure that the values are equal to within some reasonable precision.

// are values equal to within 12 (or so) digits of precision?
//
bool ApproxEquals(double d1, double d2) {
    return Math.Abs(d1 - d2) < (Math.Abs(d1) * 1e-12);
}

If this were C++, then you could also pull some tricks to compare the mantissa and exponent separately, but I can't think of any way to do this safely in unmanged code.

Due to the way real numbers are typically represented, You can do this in C (and probably in unsafe C#):

if (llabs(*(long long)&x - *(long long)&y) <= EPSILON) {
    // Close enough
}

This is obviously non-portable and probably a bad idea, but it has the significant advantage of scale-independence. That is, EPSILON can be some small constant like 1, 10 or 100 (depending on your desired tolerance), and it will handle proportional rounding errors correctly regardless of the exponent.

Disclaimer: This is my own private invention, and has not been vetted by anyone with a clue (like, say, a mathematician with a background in discrete arithmetic).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!