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);
}
}