Skip to content

Instantly share code, notes, and snippets.

@kameko
Created May 15, 2018 05:25
Show Gist options
  • Save kameko/0188a2dfd8ccb61658cd5acf9ab19972 to your computer and use it in GitHub Desktop.
Save kameko/0188a2dfd8ccb61658cd5acf9ab19972 to your computer and use it in GitHub Desktop.
A few static generic methods to work on number types
using System;
namespace Numbers
{
public static class GenericNumbers
{
[Flags]
public enum NumberTypes
{
None = 1 << 0,
Byte = 1 << 1,
SByte = 1 << 2,
Int16 = 1 << 3,
UInt16 = 1 << 4,
Int32 = 1 << 5,
UInt32 = 1 << 6,
Int64 = 1 << 7,
UInt64 = 1 << 8,
Single = 1 << 9,
Double = 1 << 10,
Decimal = 1 << 11,
BigInteger = 1 << 12,
}
public static NumberTypes NumberKind<T>(T obj)
{
switch (obj)
{
case Byte b: return NumberTypes.Byte;
case SByte sb: return NumberTypes.SByte;
case Int16 i16: return NumberTypes.Int16;
case UInt16 u16: return NumberTypes.UInt16;
case Int32 i32: return NumberTypes.Int32;
case UInt32 u32: return NumberTypes.UInt32;
case Int64 i64: return NumberTypes.Int64;
case UInt64 u64: return NumberTypes.UInt64;
case Single s: return NumberTypes.Single;
case Double d: return NumberTypes.Double;
case Decimal dec: return NumberTypes.Decimal;
default: return NumberTypes.None;
}
}
public static Boolean IsNumber<T>(T obj)
{
return !GenericNumbers.NumberKind<T>(obj).HasFlag(NumberTypes.None);
}
public static T Add<T>(T x, T y) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType((b + Convert.ToByte (y)), typeof(T));
case SByte sb: return (T)Convert.ChangeType((sb + Convert.ToSByte (y)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType((i16 + Convert.ToInt16 (y)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType((u16 + Convert.ToUInt16 (y)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType((i32 + Convert.ToInt32 (y)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType((u32 + Convert.ToUInt32 (y)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType((i64 + Convert.ToInt64 (y)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType((u64 + Convert.ToUInt64 (y)), typeof(T));
case Single s: return (T)Convert.ChangeType((s + Convert.ToSingle (y)), typeof(T));
case Double d: return (T)Convert.ChangeType((d + Convert.ToDouble (y)), typeof(T));
case Decimal dec: return (T)Convert.ChangeType((dec + Convert.ToDecimal (y)), typeof(T));
default: return default;
}
}
public static T Subtract<T>(T x, T y) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType((b - Convert.ToByte (y)), typeof(T));
case SByte sb: return (T)Convert.ChangeType((sb - Convert.ToSByte (y)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType((i16 - Convert.ToInt16 (y)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType((u16 - Convert.ToUInt16 (y)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType((i32 - Convert.ToInt32 (y)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType((u32 - Convert.ToUInt32 (y)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType((i64 - Convert.ToInt64 (y)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType((u64 - Convert.ToUInt64 (y)), typeof(T));
case Single s: return (T)Convert.ChangeType((s - Convert.ToSingle (y)), typeof(T));
case Double d: return (T)Convert.ChangeType((d - Convert.ToDouble (y)), typeof(T));
case Decimal dec: return (T)Convert.ChangeType((dec - Convert.ToDecimal (y)), typeof(T));
default: return default;
}
}
public static T Divide<T>(T x, T y) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType((b / Convert.ToByte (y)), typeof(T));
case SByte sb: return (T)Convert.ChangeType((sb / Convert.ToSByte (y)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType((i16 / Convert.ToInt16 (y)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType((u16 / Convert.ToUInt16 (y)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType((i32 / Convert.ToInt32 (y)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType((u32 / Convert.ToUInt32 (y)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType((i64 / Convert.ToInt64 (y)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType((u64 / Convert.ToUInt64 (y)), typeof(T));
case Single s: return (T)Convert.ChangeType((s / Convert.ToSingle (y)), typeof(T));
case Double d: return (T)Convert.ChangeType((d / Convert.ToDouble (y)), typeof(T));
case Decimal dec: return (T)Convert.ChangeType((dec / Convert.ToDecimal (y)), typeof(T));
default: return default;
}
}
public static T Multiply<T>(T x, T y) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType((b * Convert.ToByte (y)), typeof(T));
case SByte sb: return (T)Convert.ChangeType((sb * Convert.ToSByte (y)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType((i16 * Convert.ToInt16 (y)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType((u16 * Convert.ToUInt16 (y)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType((i32 * Convert.ToInt32 (y)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType((u32 * Convert.ToUInt32 (y)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType((i64 * Convert.ToInt64 (y)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType((u64 * Convert.ToUInt64 (y)), typeof(T));
case Single s: return (T)Convert.ChangeType((s * Convert.ToSingle (y)), typeof(T));
case Double d: return (T)Convert.ChangeType((d * Convert.ToDouble (y)), typeof(T));
case Decimal dec: return (T)Convert.ChangeType((dec * Convert.ToDecimal (y)), typeof(T));
default: return default;
}
}
public static T Power<T>(T x, T y) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType(Math.Pow(b , Convert.ToByte (y)), typeof(T));
case SByte sb: return (T)Convert.ChangeType(Math.Pow(sb , Convert.ToSByte (y)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType(Math.Pow(i16 , Convert.ToInt16 (y)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType(Math.Pow(u16 , Convert.ToUInt16 (y)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType(Math.Pow(i32 , Convert.ToInt32 (y)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType(Math.Pow(u32 , Convert.ToUInt32 (y)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType(Math.Pow(i64 , Convert.ToInt64 (y)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType(Math.Pow(u64 , Convert.ToUInt64 (y)), typeof(T));
case Single s: return (T)Convert.ChangeType(Math.Pow(s , Convert.ToSingle (y)), typeof(T));
case Double d: return (T)Convert.ChangeType(Math.Pow(d , Convert.ToDouble (y)), typeof(T));
// Math.Pow(Decimal, Decimal) does not exist as an overload.
default: return default;
}
}
public static T Min<T>(T x, T y) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType(Math.Min(b , Convert.ToByte (y)), typeof(T));
case SByte sb: return (T)Convert.ChangeType(Math.Min(sb , Convert.ToSByte (y)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType(Math.Min(i16 , Convert.ToInt16 (y)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType(Math.Min(u16 , Convert.ToUInt16 (y)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType(Math.Min(i32 , Convert.ToInt32 (y)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType(Math.Min(u32 , Convert.ToUInt32 (y)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType(Math.Min(i64 , Convert.ToInt64 (y)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType(Math.Min(u64 , Convert.ToUInt64 (y)), typeof(T));
case Single s: return (T)Convert.ChangeType(Math.Min(s , Convert.ToSingle (y)), typeof(T));
case Double d: return (T)Convert.ChangeType(Math.Min(d , Convert.ToDouble (y)), typeof(T));
case Decimal dec: return (T)Convert.ChangeType(Math.Min(dec , Convert.ToDecimal (y)), typeof(T));
default: return default;
}
}
public static T Max<T>(T x, T y) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType(Math.Max(b , Convert.ToByte (y)), typeof(T));
case SByte sb: return (T)Convert.ChangeType(Math.Max(sb , Convert.ToSByte (y)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType(Math.Max(i16 , Convert.ToInt16 (y)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType(Math.Max(u16 , Convert.ToUInt16 (y)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType(Math.Max(i32 , Convert.ToInt32 (y)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType(Math.Max(u32 , Convert.ToUInt32 (y)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType(Math.Max(i64 , Convert.ToInt64 (y)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType(Math.Max(u64 , Convert.ToUInt64 (y)), typeof(T));
case Single s: return (T)Convert.ChangeType(Math.Max(s , Convert.ToSingle (y)), typeof(T));
case Double d: return (T)Convert.ChangeType(Math.Max(d , Convert.ToDouble (y)), typeof(T));
case Decimal dec: return (T)Convert.ChangeType(Math.Max(dec , Convert.ToDecimal (y)), typeof(T));
default: return default;
}
}
public static T Clamp<T>(T number, T min, T max) where T : struct, IConvertible
{
switch (number)
{
case Byte b: return (T)Convert.ChangeType(Math.Clamp(b , Convert.ToByte (min), Convert.ToByte (max)), typeof(T));
case SByte sb: return (T)Convert.ChangeType(Math.Clamp(sb , Convert.ToSByte (min), Convert.ToSByte (max)), typeof(T));
case Int16 i16: return (T)Convert.ChangeType(Math.Clamp(i16 , Convert.ToInt16 (min), Convert.ToInt16 (max)), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType(Math.Clamp(u16 , Convert.ToUInt16 (min), Convert.ToUInt16 (max)), typeof(T));
case Int32 i32: return (T)Convert.ChangeType(Math.Clamp(i32 , Convert.ToInt32 (min), Convert.ToInt32 (max)), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType(Math.Clamp(u32 , Convert.ToUInt32 (min), Convert.ToUInt32 (max)), typeof(T));
case Int64 i64: return (T)Convert.ChangeType(Math.Clamp(i64 , Convert.ToInt64 (min), Convert.ToInt64 (max)), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType(Math.Clamp(u64 , Convert.ToUInt64 (min), Convert.ToUInt64 (max)), typeof(T));
case Single s: return (T)Convert.ChangeType(Math.Clamp(s , Convert.ToSingle (min), Convert.ToSingle (max)), typeof(T));
case Double d: return (T)Convert.ChangeType(Math.Clamp(d , Convert.ToDouble (min), Convert.ToDouble (max)), typeof(T));
case Decimal dec: return (T)Convert.ChangeType(Math.Clamp(dec , Convert.ToDecimal (min), Convert.ToDecimal (max)), typeof(T));
default: return default;
}
}
public static T Absolute<T>(T x) where T : struct, IConvertible
{
switch (x)
{
case Byte b: return (T)Convert.ChangeType(Math.Abs(b ), typeof(T));
case SByte sb: return (T)Convert.ChangeType(Math.Abs(sb ), typeof(T));
case Int16 i16: return (T)Convert.ChangeType(Math.Abs(i16 ), typeof(T));
case UInt16 u16: return (T)Convert.ChangeType(Math.Abs(u16 ), typeof(T));
case Int32 i32: return (T)Convert.ChangeType(Math.Abs(i32 ), typeof(T));
case UInt32 u32: return (T)Convert.ChangeType(Math.Abs(u32 ), typeof(T));
case Int64 i64: return (T)Convert.ChangeType(Math.Abs(i64 ), typeof(T));
case UInt64 u64: return (T)Convert.ChangeType(Math.Abs((Decimal)u64), typeof(T));
case Single s: return (T)Convert.ChangeType(Math.Abs(s ), typeof(T));
case Double d: return (T)Convert.ChangeType(Math.Abs(d ), typeof(T));
case Decimal dec: return (T)Convert.ChangeType(Math.Abs(dec ), typeof(T));
default: return default;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment