Как представить целочисленную бесконечность?
Мне нужен способ представления целочисленного числа, которое может быть бесконечным. Я бы предпочел не использовать тип с плавающей точкой (double.PositiveInfinity), поскольку число никогда не может быть дробным, и это может привести к запутыванию API. Каков наилучший способ сделать это?
Изменить: Одна идея, которую я еще не видел, это использовать int? с нулем, представляющим бесконечность. Есть ли веские причины не делать этого?
Ответы
Ответ 1
Если вам не нужен полный диапазон целочисленных значений, вы можете использовать константы int.MaxValue
и int.MinValue
для представления бесконечностей.
Однако, если требуется полный диапазон значений, я бы предложил либо создать класс-оболочку, либо просто перейти к удвоению.
Ответ 2
Пример частичной реализации в соответствии с комментариями SLaks и других (приветствие приветствия):
Применение:
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);
Реализация:
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 */
}
Ответ 3
Ваш API может использовать соглашение, что int.MaxValue
представляет положительное значение бесконечности и int.MinValue
- отрицательную бесконечность.
Но вам все равно нужно документировать его где-нибудь и, возможно, вам понадобятся некоторые операции с вашим бесконечным целым числом:
/// <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;
}
}
Ответ 4
Другая частичная реализация (я вижу, что Джек был быстрее):
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
}
Ответ 5
У С# есть тип для этого класса BigInteger - неограниченный размер
http://msdn.microsoft.com/en-us/library/system.numerics.biginteger.aspx
Если вы хотите, чтобы класс имел представление бесконечности, тогда сверните BigInteger в класс, который дает ему флаг бесконечности.
Вам нужно будет переопределить все стандартные операторы и преобразования, чтобы заставить это работать.
Как точно работать с бесконечной работой зависит от вашего домена.
(Например, в некоторых формах математики вы хотели бы 2 x бесконечность = бесконечность, а в некоторых вы этого не сделали).
Как будут реализованы детали, действительно зависит от проблемы вашего домена и неясны из вашего вопроса.