Upsilon/Upsilon/BaseTypes/Number/ScriptNumber.cs

169 lines
7.3 KiB
C#

using System;
namespace Upsilon.BaseTypes.Number
{
public abstract class ScriptNumber : ScriptType
{
protected internal abstract bool IsFloat { get; }
public override TypeContainer Type => BaseTypes.Type.Number;
#region Binary Operators
public static ScriptNumber operator + (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value + ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value + ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value + ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value + ((ScriptNumberDouble) b).Value);
}
public static ScriptNumber operator - (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value - ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value - ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value - ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value - ((ScriptNumberDouble) b).Value);
}
public static ScriptNumber operator * (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value * ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value * ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value * ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value * ((ScriptNumberDouble) b).Value);
}
public static ScriptNumber operator % (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value % ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value % ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value % ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value % ((ScriptNumberDouble) b).Value);
}
public static ScriptNumber operator / (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberLong) a).Value / (double)((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value / ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value / ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value / ((ScriptNumberDouble) b).Value);
}
#endregion
public static ScriptNumber operator - (ScriptNumber n)
{
if (n.IsFloat)
return new ScriptNumberDouble(-((ScriptNumberDouble)n).Value);
return new ScriptNumberLong(-((ScriptNumberLong)n).Value);
}
public static ScriptNumber Exponent(ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong((long) Math.Pow(((ScriptNumberLong) a).Value, ((ScriptNumberLong) b).Value));
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(Math.Pow(((ScriptNumberDouble) a).Value, ((ScriptNumberDouble) b).Value));
if (a.IsFloat)
return new ScriptNumberDouble(Math.Pow(((ScriptNumberDouble) a).Value, ((ScriptNumberLong) b).Value));
return new ScriptNumberDouble(Math.Pow(((ScriptNumberLong) a).Value, ((ScriptNumberDouble) b).Value));
}
#region Equality
private bool Equals(ScriptNumber other)
{
if (!IsFloat && !other.IsFloat)
return ((ScriptNumberLong) this).Value.Equals(((ScriptNumberLong) other).Value);
if (IsFloat && other.IsFloat)
return ((ScriptNumberDouble) this).Value.Equals(((ScriptNumberDouble) other).Value);
return false;
}
#pragma warning disable 659
public override bool Equals(object obj)
#pragma warning restore 659
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (IsFloat && obj is double d)
{
return Math.Abs(((ScriptNumberDouble) this).Value - d) < 0.0000001;
}
if (!IsFloat && obj is long l)
{
return ((ScriptNumberLong) this).Value == l;
}
if (obj.GetType() != this.GetType()) return false;
return Equals((ScriptNumber) obj);
}
#endregion
public static ScriptBoolean operator < (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptBoolean(((ScriptNumberLong) a).Value < ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptBoolean(((ScriptNumberDouble) a).Value < ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptBoolean(((ScriptNumberDouble) a).Value < ((ScriptNumberLong) b).Value);
return new ScriptBoolean(((ScriptNumberLong) a).Value < ((ScriptNumberDouble) b).Value);
}
public static ScriptBoolean operator > (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptBoolean(((ScriptNumberLong) a).Value > ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptBoolean(((ScriptNumberDouble) a).Value > ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptBoolean(((ScriptNumberDouble) a).Value > ((ScriptNumberLong) b).Value);
return new ScriptBoolean(((ScriptNumberLong) a).Value > ((ScriptNumberDouble) b).Value);
}
public static ScriptBoolean operator <= (ScriptNumber a, ScriptNumber b)
{
return (a < b) || a.Equals(b);
}
public static ScriptBoolean operator >= (ScriptNumber a, ScriptNumber b)
{
return !(a < b) || a.Equals(b);
}
public static explicit operator double(ScriptNumber n)
{
if (n.IsFloat)
return ((ScriptNumberDouble) n);
return ((ScriptNumberLong) n).Value;
}
public static explicit operator long(ScriptNumber n)
{
if (n.IsFloat)
return (long)((ScriptNumberDouble) n).Value;
return ((ScriptNumberLong) n).Value;
}
}
}