Question

I need a way to represent an integer number that can be infinite. I'd prefer not to use a floating point type (double.PositiveInfinity) since the number can never be fractional and this might make the API confusing. What is the best way to do this?

Edit: One idea I haven't seen yet is using int? with null representing infinity. Are there any good reasons not to do this?

Était-ce utile?

La solution

If you don't need the full range of integer values, you can use the int.MaxValue and int.MinValue constants to represent infinities.

However, if the full range of values is required, I'd suggest either creating a wrapper class or simply going for doubles.

Autres conseils

An example partial implementation along the lines of the comments of SLaks and others (feedback welcome):

Usage:

int x = 4;
iint pi = iint.PositiveInfinity;
iint ni = iint.NegativeInfinity;

Assert.IsTrue(x + pi == iint.PositiveInfinity);
Assert.IsTrue(pi + 1 == iint.PositiveInfinity);
Assert.IsTrue(pi + (-ni) == iint.PositiveInfinity);
Assert.IsTrue((int)((iint)5) == 5);

Implementation:

public struct iint
{
    private readonly int _int;

    public iint(int value) 
    {
        if(value  == int.MaxValue || value == int.MinValue)
            throw new InvalidOperationException("min/max value reserved in iint");
        _int = value;
    }

    public static explicit operator int(iint @this)
    {
        if(@this._int == int.MaxValue || @this._int == int.MinValue)
            throw new InvalidOperationException("cannot implicit convert infinite iint to int");

        return @this._int;
    }

    public static implicit operator iint(int other)
    {
        if(other == int.MaxValue || other == int.MinValue)
            throw new InvalidOperationException("cannot implicit convert max-value into to iint");
        return new iint(other);
    }

    public bool IsPositiveInfinity {get { return _int == int.MaxValue; } }

    public bool IsNegativeInfinity { get { return _int == int.MinValue; } }

    private iint(bool positive)
    {
        if (positive)
            _int = int.MaxValue;
        else
            _int = int.MinValue;
    }

    public static readonly iint PositiveInfinity = new iint(true);

    public static readonly iint NegativeInfinity = new iint(false);

    public static bool operator ==(iint a, iint b)
    {
        return a._int == b._int;
    }

    public static bool operator !=(iint a, iint b)
    {
        return a._int != b._int;
    }

    public static iint operator +(iint a, iint b)
    {
        if (a.IsPositiveInfinity && b.IsNegativeInfinity)
            throw new InvalidOperationException();
        if (b.IsPositiveInfinity && a.IsNegativeInfinity)
            throw new InvalidOperationException();
        if (a.IsPositiveInfinity)
            return PositiveInfinity;
        if (a.IsNegativeInfinity)
            return NegativeInfinity;
        if (b.IsPositiveInfinity)
            return PositiveInfinity;
        if (b.IsNegativeInfinity)
            return NegativeInfinity;

        return a._int + b._int;
    }

    public static iint operator -(iint a, iint b)
    {
        if (a.IsPositiveInfinity && b.IsPositiveInfinity)
            throw new InvalidOperationException();
        if (a.IsNegativeInfinity && b.IsNegativeInfinity)
            throw new InvalidOperationException();
        if (a.IsPositiveInfinity)
            return PositiveInfinity;
        if (a.IsNegativeInfinity)
            return NegativeInfinity;
        if (b.IsPositiveInfinity)
            return NegativeInfinity;
        if (b.IsNegativeInfinity)
            return PositiveInfinity;

        return a._int - b._int;
    }

    public static iint operator -(iint a)
    {
        if (a.IsNegativeInfinity)
            return PositiveInfinity;
        if (a.IsPositiveInfinity)
            return NegativeInfinity;

        return -a;
    }

    /* etc... */
    /* other operators here */
}

Your API can use a convention that int.MaxValue represents positive infinity value and int.MinValue - negative infinity.

But you still need to document it somewhere and, may be you will need some operations with your infinite integer:

 /// <summary>
/// Making int infinity
/// ...
/// </summary>
public static class IntExtension
{

    public const int PositiveInfinity = int.MaxValue;

    public const int NegativeInfinity = int.MinValue;

    public static bool IsPositiveInfinity(this int x)
    {
        return x == PositiveInfinity;
    }

    public static bool IsNegativeInfinity(this int x)
    {
        return x == NegativeInfinity;
    }

    public static int Operation(this int x, int y)
    {
        // ...

        return PositiveInfinity;
    }
}

Another partial implementation (I see Jack was faster):

struct InfinityInt
{
  readonly int Value;

  InfinityInt(int value, bool allowInfinities)
  {
    if (!allowInfinities && (value == int.MinValue || value == int.MaxValue))
      throw new ArgumentOutOfRangeException("value");
    Value = value;
  }

  public InfinityInt(int value)
    : this(value, false)
  {
  }

  public static InfinityInt PositiveInfinity = new InfinityInt(int.MaxValue, true);

  public static InfinityInt NegativeInfinity = new InfinityInt(int.MinValue, true);

  public bool IsAnInfinity
  {
    get { return Value == int.MaxValue || Value == int.MinValue; }
  }

  public override string ToString()
  {
    if (Value == int.MinValue)
      return double.NegativeInfinity.ToString();
    if (Value == int.MaxValue)
      return double.PositiveInfinity.ToString();

    return Value.ToString();
  }

  public static explicit operator int(InfinityInt ii)
  {
    if (ii.IsAnInfinity)
      throw new OverflowException();
    return ii.Value;
  }
  public static explicit operator double(InfinityInt ii)
  {
    if (ii.Value == int.MinValue)
      return double.NegativeInfinity;
    if (ii.Value == int.MaxValue)
      return double.PositiveInfinity;

    return ii.Value;
  }
  public static explicit operator InfinityInt(int i)
  {
    return new InfinityInt(i); // can throw
  }
  public static explicit operator InfinityInt(double d)
  {
    if (double.IsNaN(d))
      throw new ArgumentException("NaN not supported", "d");
    if (d >= int.MaxValue)
      return PositiveInfinity;
    if (d <= int.MinValue)
      return NegativeInfinity;

    return new InfinityInt((int)d);
  }

  static InfinityInt FromLongSafely(long x)
  {
    if (x >= int.MaxValue)
      return PositiveInfinity;
    if (x <= int.MinValue)
      return NegativeInfinity;

    return new InfinityInt((int)x);
  }

  public static InfinityInt operator +(InfinityInt a, InfinityInt b)
  {
    if (a.IsAnInfinity || b.IsAnInfinity)
    {
      if (!b.IsAnInfinity)
        return a;
      if (!a.IsAnInfinity)
        return b;
      if (a.Value == b.Value)
        return a;

      throw new ArithmeticException("Undefined");
    }
    return FromLongSafely((long)a.Value + (long)b.Value);
  }
  public static InfinityInt operator *(InfinityInt a, InfinityInt b)
  {
    if (a.IsAnInfinity || b.IsAnInfinity)
    {
      if (a.Value == 0 || b.Value == 0)
        throw new ArithmeticException("Undefined");

      return (a.Value > 0) == (b.Value > 0) ? PositiveInfinity : NegativeInfinity;
    }
    return FromLongSafely((long)a.Value * (long)b.Value);
  }

  // and so on, and so on
}

C# has a type for this the BigInteger class is unlimited size

http://msdn.microsoft.com/en-us/library/system.numerics.biginteger.aspx

If you want the class to have a representation of infinity -- then wrap BigInteger in a class that gives it an infinity flag.

You will have to redefine all standard operators and conversions to get this to work.

How exactly to have operations on infinity work depends on your domain.

(For example in some forms of math you would like 2 x infinity = infinity and in some you don't).

How the details are implemented really depend on your domain problem and are not clear from your question.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top