I am writing numerical calculation software using .NET C#, which needs to be blazingly fast. There is a lot of fractional math. So using decimal
type is pretty much out of the question, given its poor speed relative to using double
. But of course double
has its problems testing for equality, with floating point rounding issues.
My options seem to be subclassing double
and overriding ==
, <
and >
; versus creating extension methods for double
equivalent to these. My tendency is to go with the latter – less code to change and maybe it will be less confusing to others reading the code later? Is there another option? What are other good reasons to choose one over the other?
Best Answer
No, that is not true. "double" does not have such problems. Equality testing for double values is well defined and usually works as it should (which may sometimes not be what several programmers expect, of course).
Truth is: programmers have often problems with testing for equality correctly in numerical software. You cannot simply fix this by using another data type, or by providing some standard equality comparers with some standard precision for equality up-front. Though such approaches may be part of a solution, you first and foremost need to make sure the programmers in your team know how to do floating point comparisons correctly.
Before reading the rest of my answer, please have a look into "What Every Computer Scientist Should Know About Floating-Point Arithmetic". Now. No excuses.
So, since you read this paper, you now have learned that there are several alternatives on how comparisons can be done when using floating point numbers, and one has to pick the correct one for the specific case. For example, it may be necessary to take absolute or relative errors into account, to analyse the required precision for each individual comparison/quantity, or to take the specific operations and algorithms into account which will be used in the numerical software you are designing. Another thing which might be necessary is to adapt the scaling of some quantities, or other measures to keep rounding errors under control.
To find out what one really needs, I would recommend starting to implement some of the algorithms and determine precisely which kind of floating point comparisons are required there. When comparisons of the same kind occur more than two or three times, then it is time to refactor them into a reusable library (maybe using extension methods, which is a useful way in C# whenever it comes to adding some reuseable methods to an existing type one cannot change). It should be clear now why overloading an operator like
==
is not useful, since there is only one such operator per type, with no additional parameters like aprecision
.Don't try this up-front until you have already written several of such numerical programs!