Created
June 28, 2023 17:45
-
-
Save AdamWhiteHat/728186383f61dd6aab2134f937393cdd to your computer and use it in GitHub Desktop.
Interval arithmetic type class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Interval arithmetic type class | |
/// </summary> | |
public class Interval : IEquatable<Interval>, IComparable<Interval>, IComparable | |
{ | |
#region Properties | |
public static Interval Zero; | |
public static Interval One; | |
public BigInteger Min { get; private set; } | |
public BigInteger Max { get; private set; } | |
public BigInteger Size { get { return Max - Min; } } | |
public BigInteger ArithmeticAverage { get { return (Min + Max) / 2; } } | |
//public BigInteger GeometricAverage { get { return (Min * Max).SquareRoot(); } } | |
#endregion | |
#region Constructors | |
public Interval() : this(0) { } | |
public Interval(BigInteger value) : this(value, value) { } | |
public Interval(BigInteger min, BigInteger max) | |
{ | |
Min = min; | |
Max = max; | |
} | |
static Interval() | |
{ | |
Zero = new Interval(0); | |
One = new Interval(1); | |
} | |
public static Interval Combine(Interval left, Interval right) | |
{ | |
if (Interval.IsDisjoint(left, right)) { throw new ArgumentOutOfRangeException($"Parameters {nameof(left)} and {nameof(right)} must overlap."); } | |
Interval first = left; | |
Interval second = right; | |
if (right < left) | |
{ | |
first = right; | |
second = left; | |
} | |
return new Interval(BigInteger.Min(first.Min, second.Min), BigInteger.Max(first.Max, second.Max)); | |
} | |
#endregion | |
#region Operations | |
public static Interval Add(Interval left, Interval right) => new Interval((left.Min + right.Min), (left.Max + right.Max)); | |
public static Interval Subtract(Interval left, Interval right) => new Interval((left.Min - right.Max), (left.Max - right.Min)); | |
public static Interval Divide(Interval left, Interval right) => new Interval(left.Min / right.Max, left.Max / right.Min); | |
public static Interval Multiply(Interval left, Interval right) => | |
new Interval( | |
CollectionMin(left.Min * right.Min, left.Min * right.Max, left.Max * right.Min, left.Max * right.Max), | |
CollectionMax(left.Min * right.Min, left.Min * right.Max, left.Max * right.Min, left.Max * right.Max) | |
); | |
public static Interval Negate(Interval value) => Interval.Subtract(Interval.Zero, value); | |
public static Interval Clone(Interval value) => new Interval(value.Min, value.Max); | |
private static BigInteger CollectionMin(params BigInteger[] elements) { return elements.Min(); } | |
private static BigInteger CollectionMax(params BigInteger[] elements) { return elements.Max(); } | |
#endregion | |
#region Operators | |
#region Arithmetic Operators | |
public static Interval operator +(Interval left, Interval right) => Interval.Add(left, right); | |
public static Interval operator -(Interval left, Interval right) => Interval.Subtract(left, right); | |
public static Interval operator *(Interval left, Interval right) => Interval.Multiply(left, right); | |
public static Interval operator /(Interval left, Interval right) => Interval.Divide(left, right); | |
public static Interval operator -(Interval value) => Interval.Negate(value); | |
#endregion | |
#region Comparison Operators | |
public static bool operator ==(Interval left, Interval right) => Interval.Equals(left, right); | |
public static bool operator !=(Interval left, Interval right) => !Interval.Equals(left, right); | |
public static bool operator <(Interval left, Interval right) => (left.Min <= right.Min) && (left.Max < right.Max); | |
public static bool operator >(Interval left, Interval right) => (right.Max >= left.Max) && (right.Min > left.Min); | |
public static bool operator <=(Interval left, Interval right) => (left < right) || (left.Max == right.Max); | |
public static bool operator >=(Interval left, Interval right) => (right > left) || (right.Min == left.Min); | |
#endregion | |
#region Conversion Operators | |
public static implicit operator Interval(int value) => new Interval(value); | |
public static implicit operator Interval(BigInteger value) => new Interval(value); | |
#endregion | |
#endregion | |
#region Equality / CompareTo | |
public static bool Equals(Interval left, Interval right) | |
{ | |
return (left.Min == right.Min && left.Max == right.Max); | |
} | |
public bool Equals(Interval other) | |
{ | |
return this.Equals(other); | |
} | |
public int CompareTo(object obj) | |
{ | |
return this.CompareTo(obj as Interval); | |
} | |
public int CompareTo(Interval other) | |
{ | |
if (Interval.Equals(this, other)) { return 0; } | |
else if (this > other) { return 1; } | |
else if (this < other) { return -1; } | |
else if (this >= other) { return 1; } | |
else if (this <= other) { return -1; } | |
else { throw new Exception(); } | |
} | |
#endregion | |
#region Membership | |
public bool Contains(BigInteger value) | |
{ | |
return (value >= this.Min && value <= this.Max); | |
} | |
public static bool IsDisjoint(Interval left, Interval right) | |
{ | |
return !(left.Contains(right.Min) || left.Contains(right.Max)); | |
} | |
#endregion | |
#region Overrides | |
public override bool Equals(object obj) | |
{ | |
return Interval.Equals(this, obj as Interval); | |
} | |
public override int GetHashCode() | |
{ | |
return new Tuple<BigInteger, BigInteger>(this.Min, this.Max).GetHashCode(); | |
} | |
public override string ToString() | |
{ | |
if (Min == Max) | |
{ | |
return $"{Min}"; | |
} | |
else | |
{ | |
return $"[{Min},{Max}]"; | |
} | |
} | |
#endregion | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class IntervalExtensionMethods | |
{ | |
public static bool ContainsZero(this Interval source) | |
{ | |
return (source.Min.Sign != source.Max.Sign); | |
} | |
public static Interval MiddleThird(this Interval source) | |
{ | |
BigInteger oneThird = DivideInterval(source, 3); | |
return new Interval(source.Min + oneThird, source.Max - oneThird); | |
} | |
public static (Interval, Interval) Bisect(this Interval source) | |
{ | |
BigInteger midPoint = source.MidPoint(); | |
Interval left = new Interval(source.Min, midPoint); | |
Interval right = new Interval(midPoint, source.Max); | |
return (left, right); | |
} | |
public static BigInteger MidPoint(this Interval source) | |
{ | |
return DivideInterval(source, 2); | |
} | |
public static BigInteger DivideInterval(this Interval source, BigInteger divisor) | |
{ | |
BigInteger adjust = -(source.Min); | |
BigInteger min = source.Min + adjust; | |
BigInteger max = source.Max + adjust; | |
BigInteger result = (max - min) / divisor; | |
result = result - adjust; | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment