HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Universal number comparer

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
universalnumbercomparer

Problem

I wrote some code which compares numbers of all datatypes with each other.
The standard Comparer which is implemented by every number Type only compares numbers of the same type.

I cast to decimal because this is the largest possible number type and should cover everything.

  • What do you think about the code?



  • Is there any room for improvement?



  • How can I handle NaN the best way?



  • Do you think BigInt and Real numbers should be a part of it?



public class UniversalNumberComparer: IComparer
{
    public int Compare(object x, object y)
    {
        if(!IsNumber(x) || !IsNumber(y))
            throw new InvalidOperationException();

        if(x == null) 
        {
            return y == null
                ? 0
                : -1;
        }
        else
        {
            if(y == null)
                return 1;
        }

        return Decimal.Compare(Convert.ToDecimal(x), Convert.ToDecimal(y));
    }

    private bool IsNumber(object value)
    {
        if(value is sbyte || value is sbyte?)
            return true;
        if(value is byte || value is byte?)
            return true;
        if(value is short || value is short?)
            return true;
        if(value is ushort || value is ushort?)
            return true;
        if(value is int || value is int?)
            return true;
        if(value is uint || value is uint?)
            return true;
        if(value is long || value is long?)
            return true;
        if(value is ulong || value is ulong?)
            return true;
        if(value is float || value is float?)
            return true;
        if(value is double || value is double?)
            return true;
        if(value is decimal || value is decimal?)
            return true;
        return false;
    }
}

Solution

As for your question about NaN: this is also a situation where conversion to decimal is likely to be problematic. Assuming that you resolve that problem, the question then is what to do about it in the comparison.

It depends on the goals of your comparison. The semantics of NaN are "this thing isn't even a number, so asking which one is bigger is a nonsensical question", and therefore any operation on NaN is false. That means that NaN is not greater than any number, not smaller than any number and not equal to any number, including itself. If that's acceptable for your comparison purposes then that's the semantics you should implement.

Those semantics are not acceptable for sorting. If the comparison is being used in a comparison sort then the comparison is required to produce a total consistent order. It must be reflexive -- every number must equal itself. It must be antisymmetric -- if a < b is true then b < a must be false. And it must be transitive -- if a < b is true and b < c is true then a < c must be true. The usual way to deal with NaNs is to say that all NaNs are equal to each other -- achieving reflexivity, and that all NaNs are smaller than every non-NaN -- achieving antisymmetry and transitivity.

And don't forget that you'll need to deal with positive and negative infinities.

Context

StackExchange Code Review Q#23422, answer score: 6

Revisions (0)

No revisions yet.