using System; namespace Chernobyl.Calculator { /// /// This class is to be used with the ICalculator so that operators can be used with types in /// generic programming. This class does not infer any additional overhead versus straight operator /// invocation because of inlining methods on constrained parameters (see reference link below). /// References: the idea for this class came from: http://www.codeproject.com/KB/cs/genericnumerics.aspx /// /// The number type being represented such as float, int, etc. /// The calculator being used to calculate the represented /// data such as FloatCalculator, IntCalculator, etc. [Serializable] public struct Number where CalculatorType : ICalculator, new() { /// /// Constructor. /// /// The value to set the number to. private Number(NumberType value) { this.value = value; } /// /// Converts from the number type being represented to a Number. /// /// The number to convert to a Number /// The representative Number object. public static implicit operator Number(NumberType number) { return new Number(number); } /// /// Converts from the Number object to its number type. /// /// The number object to convert. /// The value of the number object. public static implicit operator NumberType(Number number) { return number.value; } /// /// Adds two Number objects. /// /// The left side of the operation. /// The right side of the operation. /// The result of the operation. public static Number operator +(Number left, Number right) { return calculator.Add(left.value, right.value); } /// /// Subtracts two Number objects. /// /// The left side of the operation. /// The right side of the operation. /// The result of the operation. public static Number operator -(Number left, Number right) { return calculator.Subtract(left.value, right.value); } /// /// Multiplies two Number objects. /// /// The left side of the operation. /// The right side of the operation. /// The result of the operation. public static Number operator *(Number left, Number right) { return calculator.Multiply(left.value, right.value); } /// /// Divides two Number objects. /// /// The left side of the operation. /// The right side of the operation. /// The result of the operation. public static Number operator /(Number dividend, Number divisor) { return calculator.Divide(dividend.value, divisor.value); } /// /// Negates a number /// /// The item to negate. /// The result of the operation. public static Number operator -(Number item) { return calculator.Negate(item.value); } /// /// Checks if two numbers are equal to each other. /// /// The left side of the operation. /// The right side of the operation. /// True if the two are equal, false if otherwise. public static bool operator ==(Number left, Number right) { return calculator.Compare(left.value, right.value); } /// /// Checks if two numbers are equal to each other. /// /// The left side of the operation. /// The right side of the operation. /// True if the two are different, false if otherwise. public static bool operator !=(Number left, Number right) { return !calculator.Compare(left.value, right.value); } /// /// Gets the hash code of the number. /// /// The hash code of the number. public override int GetHashCode() { return value.GetHashCode(); } /// /// Checks this object for equality with object passed in. /// /// The object to compare to. /// public override bool Equals(object obj) { return value.Equals(obj); } /// /// The calculator used to calculate the value of number. /// static CalculatorType calculator = new CalculatorType(); /// /// The number that is being represented by this struct. /// NumberType value; } /// /// Extension and utility methods for numbers. /// public static class Number { /// /// Rounds a floating point value to an integer (.5 and above will be rounded up, everything /// else will be rounded down). /// public static int RoundToInt(this float v) => (int)Math.Round(v, MidpointRounding.AwayFromZero); /// /// Rounds a floating point value to an integer (.5 and above will be rounded up, everything /// else will be rounded down). /// public static int RoundToInt(this double v) => (int)Math.Round(v, MidpointRounding.AwayFromZero); } }