Choosing an Epsilon Value for Floating Point Comparisons

谁说我不能喝 提交于 2019-12-22 11:05:10

问题


My team is working with financial software that exposes monetary values as C# floating point doubles. Occasionally, we need to compare these values to see if they equal zero, or fall under a particular limit. When I noticed unexpected behavior in this logic, I quickly learned about the rounding errors inherent in floating point doubles (e.g. 1.1 + 2.2 = 3.3000000000000003). Up until this point, I have primarily used C# decimals to represent monetary values.

My team decided to resolve this issue by using the epsilon value approach. Essentially, when you are compare two numbers, if the difference between those two numbers is less than epsilon, they are considered equal. We implemented this approach in a similar way as described in the article below: https://www.codeproject.com/Articles/383871/Demystify-Csharp-floating-point-equality-and-relat

Our challenge has been determining an appropriate value for epsilon. Our monetary values can have up to 3 digits to the right of the decimal point (scale = 3). This means that the largest epsilon we could use is .0001 (anything larger and the 3rd digit gets ignored). Since epsilon values are supposed to be small, we decided to move it out one more decimal point to .00001 (just to be safe, you could say). C# doubles have a precision of at least 15 digits, so I believe this value of epsilon should work if the number to the left of the decimal point is less or equal to 10 digits (15 - 5 = 10, where 5 is the number of digits epsilon is to the right of the decimal point). With 10 digits, we can represent values into the billions, up to 9,999,999,999.999. It's possible that we may have numbers in the hundreds of millions, but we don't expect to go into the billions, so this limit should suffice.

Is my rationale for choosing this value of epsilon correct? I found a lot of resources that discuss this approach, but I couldn’t find many resources that provide guidance on choosing epsilon.


回答1:


Your reasoning seems sound, but as you have already discovered it is a complicated issue. You might want to read What Every Computer Scientist Should Know About Floating-Point Arithmetic. You do have a minimum of 15 digits of precision using 64 bit doubles. However, you will also want to validate your inputs as floats can contain Nan, +/- Infinity, negative zero and a considerably larger "range" than 15 decimal digits. If someone hands your library a value like 1.2E102, should you process it or consider it out of range? Ditto with very small values. Garbage In, Garbage out, but it might be nice if you code detected the "smell" of garbage and at very least logged it.

You might also want to consider providing a property for setting precision as well as different forms of rounding. That depends largely on the specifications you are working with. You might also want to determine if these values can represent currencies other than dollars (1 dollar is currently >112 yen).

Long and the short of it choosing your epsilon a digit below your needs (so four digits to the right of the decimal) is sound and gives you a digit to use for consistent rounding. Otherwise $10.0129 and $10.0121 would be equal but their sum would be $20.025 rather than $20.024 ... accountants like things that "foot".



来源:https://stackoverflow.com/questions/46652980/choosing-an-epsilon-value-for-floating-point-comparisons

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