using System; using System.Runtime.CompilerServices; namespace GlitchyEngine.Math; /// /// Represents a 16-bit (half-precision) floating point number. (aka. IEEE 754 half-precision binary floating-point (binary16)) /// /// /// Even though it is possible, it's not recommended to perform large calculations using this type directly because most operators will simply cast the operands to and cast the result back to . /// If you need to do larger calculations consider casting to once and cast the result back to afterwards. This will not only have better performance, but will also increase the accuracy of the result. /// public struct Half : IComparable , IComparable, IConvertible, IEquatable, IFormattable { public static readonly Half MinValue = new(-65504); // Should be 0xFBFF public static readonly Half MaxValue = new(65504); // Should be 0x7BFF // The numbers for Infinity, NaN and Zero need to be hardcoded as binaries, // because the conversion itself relies on them. public static readonly Half PositiveInfinity = new(0x7C00); public static readonly Half NegativeInfinity = new(0xFC00); public static readonly Half NaN = new(0x7CFF); public static readonly Half Zero = new(0x0000); public static readonly Half NegativeZero = new(0x8000); private ushort _data; public bool IsNegative => IsNegative_Impl(this); public bool IsFinite => IsFinite_Impl(this); public bool IsInfinity => IsInfinity_Impl(this); public bool IsPositiveInfinity => _data == PositiveInfinity._data; public bool IsNegativeInfinity => _data == NegativeInfinity._data; public bool IsNaN => IsNan_Impl(this); public bool IsSubnormal => IsSubnormal_Impl(this); public Half(float value) { FromFloat32(value, out Half halfValue); this = halfValue; } private Half(ushort data) { _data = data; } public static explicit operator float(Half value) { ToFloat32(value, out float floatValue); return floatValue; } public static explicit operator Half(float value) { FromFloat32(value, out Half halfValue); return halfValue; } /// Converts the numeric value of this instance to its equivalent string representation. /// The string representation of the value of this instance. public override string ToString() => ((float)this).ToString(); public int CompareTo(object obj) { if (obj == null) return 1; if (obj is not Half value) throw new ArgumentException($"Object must be of type {typeof(Half)}"); return CompareTo(value); } public int CompareTo(Half other) { return ((float)this).CompareTo((float)other); } public TypeCode GetTypeCode() => TypeCode.Object; public bool ToBoolean(IFormatProvider provider) => Convert.ToBoolean((float)this, provider); public byte ToByte(IFormatProvider provider) => Convert.ToByte((float)this, provider); public char ToChar(IFormatProvider provider) => Convert.ToChar((float)this, provider); public DateTime ToDateTime(IFormatProvider provider) => Convert.ToDateTime((float)this, provider); public decimal ToDecimal(IFormatProvider provider) => Convert.ToDecimal((float)this, provider); public double ToDouble(IFormatProvider provider) => Convert.ToDouble((float)this, provider); public short ToInt16(IFormatProvider provider) => Convert.ToInt16((float)this, provider); public int ToInt32(IFormatProvider provider) => Convert.ToInt32((float)this, provider); public long ToInt64(IFormatProvider provider) => Convert.ToInt64((float)this, provider); public sbyte ToSByte(IFormatProvider provider) => Convert.ToSByte((float)this, provider); public float ToSingle(IFormatProvider provider) => Convert.ToSingle((float)this, provider); /// Converts the numeric value of this instance to its equivalent string representation using the specified culture-specific format information. /// An object that supplies culture-specific formatting information. /// The string representation of the value of this instance as specified by provider. public string ToString(IFormatProvider provider) => ((float)this).ToString(provider); /// Converts the numeric value of this instance to its equivalent string representation, using the specified format. /// A numeric format string. /// The string representation of the value of this instance as specified by format. /// format is invalid. public string ToString(string format) => ((float)this).ToString(format); /// Converts the numeric value of this instance to its equivalent string representation using the specified format and culture-specific format information. /// A numeric format string. /// An object that supplies culture-specific formatting information. /// The string representation of the value of this instance as specified by format and provider. public string ToString(string format, IFormatProvider provider) => ((float)this).ToString(format, provider); public object ToType(Type conversionType, IFormatProvider provider) => ((IConvertible)(float)this).ToType(conversionType, provider); public ushort ToUInt16(IFormatProvider provider) => Convert.ToUInt16((float)this, provider); public uint ToUInt32(IFormatProvider provider) => Convert.ToUInt32((float)this, provider); public ulong ToUInt64(IFormatProvider provider) => Convert.ToUInt64((float)this, provider); public bool Equals(Half other) { return _data == other._data; } public override bool Equals(object obj) { return obj is Half other && Equals(other); } public override int GetHashCode() { return _data.GetHashCode(); } #region Operators public static bool operator ==(Half left, Half right) => left._data == right._data; public static bool operator !=(Half left, Half right) => left._data != right._data; public static bool operator <(Half left, Half right) { LessThan_Impl(left, right, out bool result); return result; } public static bool operator <=(Half left, Half right) { LessThanOrEqual_Impl(left, right, out bool result); return result; } public static bool operator >(Half left, Half right) { GreaterThan_Impl(left, right, out bool result); return result; } public static bool operator >=(Half left, Half right) { GreaterThanOrEqual_Impl(left, right, out bool result); return result; } public static Half operator +(Half value) => value; public static Half operator -(Half value) { Negate_Impl(value, out Half result); return result; } public static Half operator +(Half left, Half right) { Add_Impl(left, right, out Half result); return result; } public static Half operator -(Half left, Half right) { Subtract_Impl(left, right, out Half result); return result; } public static Half operator *(Half left, Half right) { Multiply_Impl(left, right, out Half result); return result; } public static Half operator /(Half left, Half right) { Divide_Impl(left, right, out Half result); return result; } public static Half operator %(Half left, Half right) { Modulo_Impl(left, right, out Half result); return result; } public static Half operator ++(Half value) { Increment_Impl(value, out Half result); return result; } public static Half operator --(Half value) { Decrement_Impl(value, out Half result); return result; } [MethodImpl(MethodImplOptions.InternalCall)] private static extern void LessThan_Impl(Half left, Half right, out bool result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void LessThanOrEqual_Impl(Half left, Half right, out bool result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void GreaterThan_Impl(Half left, Half right, out bool result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void GreaterThanOrEqual_Impl(Half left, Half right, out bool result); // Externe Methoden hier als Platzhalter [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Add_Impl(Half left, Half right, out Half result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Subtract_Impl(Half left, Half right, out Half result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Multiply_Impl(Half left, Half right, out Half result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Divide_Impl(Half left, Half right, out Half result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Modulo_Impl(Half left, Half right, out Half result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Negate_Impl(Half value, out Half result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Increment_Impl(Half value, out Half result); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Decrement_Impl(Half value, out Half result); #endregion #region Bindings [MethodImpl(MethodImplOptions.InternalCall)] private static extern void FromFloat32(float value, out Half halfValue); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void ToFloat32(Half value, out float floatValue); [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool IsNegative_Impl(Half self); [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool IsFinite_Impl(Half self); [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool IsInfinity_Impl(Half self); [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool IsNan_Impl(Half self); [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool IsSubnormal_Impl(Half self); #endregion }