web-dev-qa-db-ja.com

整数の無限大を表現するには?

無限の整数を表現する方法が必要です。浮動小数点型(double.PositiveInfinity)を使用したくないのは、数値が小数になることはなく、これによりAPIが混乱する可能性があるためです。これを行う最良の方法は何ですか?

編集:私はまだ見たことがない1つのアイデアはintを使用していますか? nullは無限を表します。これをしない理由はありますか?

23
ConditionRacer

整数値の全範囲が必要ない場合は、int.MaxValueおよびint.MinValue無限を表す定数。

ただし、値の全範囲が必要な場合は、ラッパークラスを作成するか、単にdoubleを使用することをお勧めします。

24
Smallhacker

SLaksおよびその他のコメントのラインに沿ったpartial実装の例(フィードバック歓迎):

使用法:

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 */
}
4
Jack

別の部分的な実装(Jackの方が高速だったようです):

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
}
1

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;
    }
}
1
astef