using System; using System.Runtime.CompilerServices; namespace GlitchyEngine.Math; /// /// Represents a 16-bit floating point number. (IEEE 754 half-precision binary floating-point (binary16)) /// /// /// Even though it is possible, it's not recommended to perform calculations using this type directly, because most operators will simply cast the operands to and cast the result back to . /// 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 Inifnity, NaN and Zero need to be hardcoded as binaries, // because the conversion intself 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 this); } 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 }