Guillaume
Guillaume

Reputation: 1802

Comparing approximate values in c# 4.0?

First of all, please excuse any typo, English is not my native language.

Here's my question. I'm creating a class that represents approximate values as such:

public sealed class ApproximateValue
{
    public double MaxValue { get; private set; }
    public double MinValue { get; private set; }
    public double Uncertainty { get; private set; }
    public double Value { get; private set; }

    public ApproximateValue(double value, double uncertainty)
    {
        if (uncertainty < 0) { throw new ArgumentOutOfRangeException("uncertainty", "Value must be postivie or equal to 0."); }

        this.Value = value;
        this.Uncertainty = uncertainty;
        this.MaxValue = this.Value + this.Uncertainty;
        this.MinValue = this.Value - this.Uncertainty;
    }
}

I want to use this class for uncertain measurments, like x = 8.31246 +/-0.0045 for example and perform calculations on these values.

I want to overload operators in this class. I don't know how to implement the >, >=, <= and < operators... The first thing I thought of is something like this:

    public static bool? operator >(ApproximateValue a, ApproximateValue b)
    {
        if (a == null || b == null) { return null; }

        if (a.MinValue > b.MaxValue) { return true; }
        else if (a.MaxValue < b.MinValue) { return false; }
        else { return null; }
    }

However, in the last case, I'm not satisfied with this 'null' as the accurate result is not 'null'. It may be 'true' or it may be 'false'.

Is there any object in .Net 4 that would help implementing this feature I am not aware of, or am I doing the correct way? I was also thinking about using an object instead of a boolean that would define in what circumstances the value is superior or not to another one rather than implementing comparison operators but I feel it's a bit too complex for what I'm trying to achieve...

Upvotes: 4

Views: 1502

Answers (5)

Steve Rowbotham
Steve Rowbotham

Reputation: 2868

It seems to me that you're trying to implement some form of Ternary Logic because you want the result of applying the operators to be either True, False or Indeterminate. The problem with doing that is that you really cannot combine the built-in boolean values with your indeterminate value. So whilst you could do some limited form of comparison of two ApproximateValues I think that it's inappropriate to use bool as the result of these comparisons because that implies that the result of the comparisons can be freely combined with other expressions that result in bool values, but the possibility of an indeterminate value undermines that. For example, it makes no sense to do the following when the result of operation on the left of the OR is indeterminate.

ApproximateValue approx1 = ...;
ApproximateValue approx2 = ...;
bool result = ...;

bool result = approx1 > approx2 || someBool; 

So, in my opinion, I don't think that it's a good idea to implement the comparisons as operators at all if you want to retain the indeterminacy. The solutions offered here eliminate the indeterminacy, which is fine, but not what was originally specified.

Upvotes: 1

James Michael Hare
James Michael Hare

Reputation: 38427

I'd probably do something like this. I'd implement IComparable<ApproximateValue> and then define <, >, <=, and >= according to the result of CompareTo():

public int CompareTo(ApproximateValue other)
{
    // if other is null, we are greater by default in .NET, so return 1.
    if (other == null)
    {
        return 1;
    }

    // this is > other
    if (MinValue > other.MaxValue)
    {
        return 1;
    }

    // this is < other
    if (MaxValue < other.MinValue)
    {
        return -1;
    }

    // "same"-ish
    return 0;
}

public static bool operator <(ApproximateValue left, ApproximateValue right)
{
    return (left == null) ? (right != null) : left.CompareTo(right) < 0;
}

public static bool operator >(ApproximateValue left, ApproximateValue right)
{
    return (right == null) ? (left != null) : right.CompareTo(left) < 0;
}

public static bool operator <=(ApproximateValue left, ApproximateValue right)
{
    return (left == null) || left.CompareTo(right) <= 0;
}

public static bool operator >=(ApproximateValue left, ApproximateValue right)
{
    return (right == null) || right.CompareTo(left) <= 0;
}

public static bool operator ==(ApproximateValue left, ApproximateValue right)
{
    return (left == null) ? (right == null) : left.CompareTo(right) == 0;
}

public static bool operator !=(ApproximateValue left, ApproximateValue right)
{
    return (left == null) ? (right != null) : left.CompareTo(left) != 0;
}

Upvotes: 3

Daren Thomas
Daren Thomas

Reputation: 70354

return a.Value - a.Uncertainty > b.Value + b.Uncertainty

I wouldn't really mess with the semantics of >: I think bool? is a dangerous return type here. That said, given the uncertainty, you could return true, if a is more likely to be > b.

Upvotes: 1

Dan Bryant
Dan Bryant

Reputation: 27515

This is one of the rare cases where it may make more sense to define a value type (struct), which then eliminates the null case concern. You can also modify MinValue and MaxValue to be computed properties (just implement a get method that computes the result) rather than storing them upon construction.

On a side note, comparison of approximate values is itself an approximate operation, so you need to consider the use cases for your data type; are you only intending to use comparison to determine when the ranges are non-overlapping? It really depends on the meaning of your type. Is this intended to represent a data point from a normally distributed data set, where the uncertainty is some number of standard deviations for the sampling? If so, it might make more sense for a comparison operation to return a numeric probability (which couldn't be called through the comparison operator, of course.)

Upvotes: 1

Bradley Uffner
Bradley Uffner

Reputation: 17001

It looks to me like you need to check if a.MaxValue == b.MinValue also, in your current implementation that would return null, which seems incorrect, it should either return true or false based on how you want the spec to actually work. I'm not sure of any built in .net functionality for this, so I believe you are going about it the correct way.

Upvotes: 1

Related Questions