34

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?

Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148
ConditionRacer
  • 4,418
  • 6
  • 45
  • 67
  • 14
    Make a wrapper type with an infinity flag. – SLaks Jan 23 '14 at 15:14
  • 1
    And that wrapper type could hold just one `int` internally. Under the convention that `int.MaxValue` represented not itself, but infinity. – Jeppe Stig Nielsen Jan 23 '14 at 15:16
  • 2
    Make a `Nullable` and treat the value `null` as infinite. – Mr Lister Jan 23 '14 at 15:17
  • 1
    what happens when you subtract `1`? `OutOfMemoryException`? – Jodrell Jan 23 '14 at 15:17
  • @JeppeStigNielsen I'd just copy the null model Nullable – Liath Jan 23 '14 at 15:18
  • @MrLister: What about negative infinity? – SLaks Jan 23 '14 at 15:18
  • @MrLister: But arithmetic will be slower, and the types will be misleading. – SLaks Jan 23 '14 at 15:20
  • 5
    @MrLister, there are a lot of integer values between `double.MaxValue` and infinity. An infinite amount infact. – Jodrell Jan 23 '14 at 15:20
  • @Jodrell Not for a `double` there aren't. – Mr Lister Jan 23 '14 at 15:21
  • @SLaks I have not done any measurements, but my guess is that using native types will not be _that_ much slower than using a wrapper and writing `if value==magicnumber then assume infinity` out in code. – Mr Lister Jan 23 '14 at 15:23
  • @MrLister: No; `double` arithmetic is quite a bit slower than integer arithmetic, and those `if` statements ought to not cost too much. – SLaks Jan 23 '14 at 15:24
  • @MrLister the set of integer numbers goes much higher than `double.MaxValue`, `int.MaxValue` or `ulong.MaxValue`, infact, all the way up to, but not including infinity, since infinity is not a number. `System.Numerics.BigInteger` doesen't have a max value because it can represent any integer (if you have enough memory.) – Jodrell Jan 23 '14 at 15:32
  • @Jodrell I think you should lodge a complaint with the OP, who neglected to mention how many bits the integers should have as a minimum. – Mr Lister Jan 23 '14 at 15:34

5 Answers5

44

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.

BambooleanLogic
  • 7,530
  • 3
  • 30
  • 56
5

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 */
}
Jack
  • 1,064
  • 8
  • 11
  • Upvoted. While you were posting this, I was writing very similar code (see my answer). – Jeppe Stig Nielsen Jan 23 '14 at 16:19
  • One issue I see (I guess there are issues in my post as well!) is that the sum of say 2,000,000,000 and 2,000,000,000 will "wrap-around" to a negative result. I would expect `PositiveInfinity` in that case. – Jeppe Stig Nielsen Jan 23 '14 at 16:23
1

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;
    }
}
astef
  • 8,575
  • 4
  • 56
  • 95
  • 2
    `PositiveInfinity / PositiveInfinity != 1` http://math.stackexchange.com/questions/181304/whats-infinity-divided-by-infinity – Jodrell Jan 23 '14 at 16:56
  • @Jodrell Yes, but this question is not about how to implement operations with infinities. Representing is the only task – astef Jan 24 '14 at 06:44
1

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
}
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
-3

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.

Hogan
  • 69,564
  • 10
  • 76
  • 117
  • 1
    No, a `BigInteger` cannot hold the specific value "infinite". – Jeppe Stig Nielsen Jan 23 '14 at 15:17
  • 1
    `BigInteger` can hold the whole valid range of `int` plus extra. Where some of extra can be infinite (to example, any value higher than `int.MaxValue + 1`are Infinite). Still a care should be made than using such Infinity in calculations `+Infinity - 2 = int.MaxValue - 1`, while it should still stay Infinity somehow. – Sinatr Jan 23 '14 at 15:25
  • There are a variety of BigInteger classes around, on CodePlex, CodeProject, etc, and one from MS in System.Numerics. The MS one doesn't have an Infinity flag. What quality the others are I don't know, but given most of them operate on a string representation of a number they will not be fast. – simon at rcl Jan 23 '14 at 15:30
  • 1
    @JeppeStigNielsen, is infinite a specific value? – Jodrell Jan 23 '14 at 15:33
  • @Sinatr - my point was that those functions need to added to your class to support the domain – Hogan Jan 23 '14 at 15:39
  • @Jodrell In my understanding of the question of this thread, yes. To see what I mean, the expression `new BigInteger(double.PositiveInfinity)` fails at runtime with: __System.OverflowException: BigInteger cannot represent infinity.__ – Jeppe Stig Nielsen Jan 23 '14 at 16:10