Question

What is the best way to compare decimals ?

lets say I have 2 values, like 3.45 and 3.44, what is the best way to reliably compare them ?

I was thinking of storing all numbers as 345 and 344 so that I am comparing whole numbers only, and only show to the user formatted numbers with the decimal point.

Another solution would be to use custom functions, to test of the difference, and when the difference is less than 0.01 the numbers should be equal.

What are other possible solutions (better solutions) ?

Was it helpful?

Solution

The most common technique is to use an epsilon (the second thing you described). It can be extremely difficult/impossible to make a generic epsilon that works for all input numbers nicely though. If you're dealing with numbers around 0.00001 or numbers around 1000000000 an epsilon of 0.01 would likely be horrible for you. Read this for a really comprehensive analysis of epsilon techniques.

The first solution you described is very common in time math. Everything is represented in an integer number of ticks. The ticks can represent 1 second, or 1 millisecond, or whatever you want. You can then convert them into a decimal of another unit if you like, or compare them. The only thing is that you do need to choose a tick size, and nothing can represent smaller than 1 tick unit.

OTHER TIPS

This is also known as "fuzzy comparison", allowing the two values to differ a little bit (tolerance, also known as "epsilon"). Typically, such an epsilon value is around 1E-6 to 1E-10, but you find applications in which smaller or greater values are better suitable: in your example the epsilon shouldn't be less than 1E-2 = 0.01.

Once you found an epsilon value which suits your needs, you could write the following set of comparison functions like the following (written in the common subset of C and C++; they should work for almost every object-oriented / procedural language with minor changes):

const double fuzzyEpsilon = 1E-6;  // just an example!

bool fuzzyEqual(double a, double b) {
    return (abs(a - b) <= fuzzyEpsilon);
}

bool fuzzyUnqual(double a, double b) {
    return (abs(a - b) > fuzzyEpsilon);
}

int fuzzyCompare(double a, double b) {
    return ((a - b) > fuzzyEpsilon) - ((b - a) > fuzzyEpsilon);
}

The third function returns a code of -1, 0, 1 if a < b, a == b, a > b respectively with fuzzy comparison (analogous to strcmp). The implementation assumes that the programming language implicitly converts boolean values to 0 (false) and 1 (true). If not, use the following:

int fuzzyCompare(double a, double b) {
    return (a - b) > fuzzyEpsilon ? 1 :
          ((b - a) > fuzzyEpsilon ? -1 : 0);
}

Representing decimal values in binary real is approximate, leading to a variety of odd behaviors. Accuracy often degrades with further arithmetic, particularly subtractions of nearby values. Individual values however can be cleaned up for comparison, by rounding to a minimum number of digits before comparing them. For example V = round (V * 1e14)/1e14 rounds any value V to 14 decimal digits. Two such values can be confidently compared for equality. 64-bit real has 15.65 deimal precision, so rounding to 14 digits (or less) provides some room for error.

Yes, the multiply, round( ) and divide sequence is expensive. However, decimal is a human interface, often used for monetary applications that cannot tolerate "funny" arithmetic. Being wrong is usually much worse than being slow.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top