using System; namespace Syroot.IOExtension { /// /// Represents a 16-bit half-precision floating point value according to the IEEE 754 standard. /// /// /// Examples: /// SEEEEEFF_FFFFFFFF /// 0b00000000_00000000 = 0 /// 1b00000000_00000000 = -0 /// 0b00111100_00000000 = 1 /// 0b11000000_00000000 = -2 /// 0b11111011_11111111 = 65504 (MaxValue) /// 0b01111100_00000000 = PositiveInfinity /// 0b11111100_00000000 = NegativeInfinity /// public struct Half { // ---- CONSTANTS ---------------------------------------------------------------------------------------------- /* /// /// Represents the smallest positive value greater than zero. /// public static readonly Half Epsilon = new Half(1); /// /// Represents the largest possible value of . /// public static readonly Half MaxValue = new Half(0b01111011_11111111); /// /// Represents the smallest possible value of . /// public static readonly Half MinValue = new Half(0b11111011_11111111); /// /// Represents not a number (NaN). /// public static readonly Half NaN = new Half(0b11111110_00000000); /// /// Represents negative infinity. /// public static readonly Half NegativeInfinity = new Half(0b11111100_00000000); /// /// Represents positive infinity. /// public static readonly Half PositiveInfinity = new Half(0b01111100_00000000);*/ private static readonly uint[] _mantissaTable; private static readonly uint[] _exponentTable; private static readonly uint[] _offsetTable; private static readonly ushort[] _baseTable; private static readonly byte[] _shiftTable; // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------ /// /// Initializes a new instance of the struct from the given /// representation. /// /// The raw representation of the internally stored bits. internal Half(ushort raw) { Raw = raw; } static Half() { int i; // Generate tables for Half to Single conversions. // Generate the mantissa table. _mantissaTable = new uint[2048]; // 0 => 0 _mantissaTable[0] = 0; // Transform subnormal to normalized. for (i = 1; i < 1024; i++) { uint m = ((uint)i) << 13; uint e = 0; while ((m & 0x00800000) == 0) { e -= 0x00800000; m <<= 1; } m &= ~0x00800000U; e += 0x38800000; _mantissaTable[i] = m | e; } // Normal case. for (i = 1024; i < 2048; i++) { _mantissaTable[i] = 0x38000000 + (((uint)(i - 1024)) << 13); } // Generate the exponent table. _exponentTable = new uint[64]; // 0 => 0 _exponentTable[0] = 0; for (i = 1; i < 63; i++) { if (i < 31) { // Positive numbers. _exponentTable[i] = ((uint)i) << 23; } else { // Negative numbers. _exponentTable[i] = 0x80000000 + (((uint)(i - 32)) << 23); } } _exponentTable[31] = 0x47800000; _exponentTable[32] = 0x80000000; _exponentTable[63] = 0xC7800000; // Generate the offset table. _offsetTable = new uint[64]; _offsetTable[0] = 0; for (i = 1; i < 64; i++) { _offsetTable[i] = 1024; } _offsetTable[32] = 0; // Generate tables for Single to Half conversions. //Generate the base and shift tables. _baseTable = new ushort[512]; _shiftTable = new byte[512]; for (i = 0; i < 256; i++) { int e = i - 127; if (e < -24) { // Very small numbers map to zero. _baseTable[i | 0x000] = 0x0000; _baseTable[i | 0x100] = 0x8000; _shiftTable[i | 0x000] = 24; _shiftTable[i | 0x100] = 24; } else if (e < -14) { // Small numbers map to denorms. _baseTable[i | 0x000] = (ushort)(0x0400 >> (-e - 14)); _baseTable[i | 0x100] = (ushort)((0x0400 >> (-e - 14)) | 0x8000); _shiftTable[i | 0x000] = (byte)(-e - 1); _shiftTable[i | 0x100] = (byte)(-e - 1); } else if (e <= 15) { // Normal numbers just lose precision. _baseTable[i | 0x000] = (ushort)((e + 15) << 10); _baseTable[i | 0x100] = (ushort)(((e + 15) << 10) | 0x8000); _shiftTable[i | 0x000] = 13; _shiftTable[i | 0x100] = 13; } else if (e < 128) { // Large numbers map to Infinity. _baseTable[i | 0x000] = 0x7C00; _baseTable[i | 0x100] = 0xFC00; _shiftTable[i | 0x000] = 24; _shiftTable[i | 0x100] = 24; } else { // Infinity and NaN's stay Infinity and NaN's. _baseTable[i | 0x000] = 0x7C00; _baseTable[i | 0x100] = 0xFC00; _shiftTable[i | 0x000] = 13; _shiftTable[i | 0x100] = 13; } } } // ---- PROPERTIES --------------------------------------------------------------------------------------------- /// /// Gets the internally stored value to represent the instance. /// /// Signed to get arithmetic rather than logical shifts. internal ushort Raw { get; private set; } // ---- OPERATORS ---------------------------------------------------------------------------------------------- /// /// Returns the given . /// /// The . /// The result. public static Half operator +(Half a) { return a; } /// /// Adds the first to the second one. /// /// The first . /// The second . /// The addition result. public static Half operator +(Half a, Half b) { return (Half)((float)a + (float)b); } /// /// Negates the given . /// /// The to negate. /// The negated result. public static Half operator -(Half a) { return new Half((ushort)(a.Raw ^ 0x8000)); } /// /// Subtracts the first from the second one. /// /// The first . /// The second . /// The subtraction result. public static Half operator -(Half a, Half b) { return (Half)((float)a - (float)b); } /// /// Multiplicates the first by the second one. /// /// The first . /// The second . /// The multiplication result. public static Half operator *(Half a, Half b) { return (Half)((float)a * (float)b); } /// /// Divides the first through the second one. /// /// The first . /// The second . /// The division result. public static Half operator /(Half a, Half b) { return (Half)((float)a / (float)b); } /// /// Gets a value indicating whether the first specified is the same as the second /// specified . /// /// The first to compare. /// The second to compare. /// true, if both are the same. public static bool operator ==(Half a, Half b) { return a.Equals(b); } /// /// Gets a value indicating whether the first specified is not the same as the second /// specified . /// /// The first to compare. /// The second to compare. /// true, if both are not the same. public static bool operator !=(Half a, Half b) { return !a.Equals(b); } /// /// Converts the given value to a instance. /// /// The value to represent in the new /// instance. public static explicit operator Half(Int32 value) { return (Half)(float)value; } /// /// Converts the given value to a instance. /// /// The value to represent in the new /// instance. public static explicit operator Half(Double value) { return (Half)(float)value; } /// /// Converts the given value to a instance. /// /// The value to represent in the new /// instance. public static explicit operator Half(Single value) { uint uint32 = ((DWord)value).UInt32; return new Half((ushort)(_baseTable[(uint32 >> 23) & 0x01FF] + ((uint32 & 0x007FFFFF) >> _shiftTable[(uint32 >> 23) & 0x01FF]))); } /// /// Converts the given value to a instance. /// /// The value to represent in the new /// instance. public static implicit operator Double(Half value) { return (float)value; } /// /// Converts the given value to a instance. /// /// The value to represent in the new /// instance. public static explicit operator Int32(Half value) { return (int)(float)value; } /// /// Converts the given value to a instance. /// /// The value to represent in the new /// instance. public static implicit operator Single(Half value) { DWord result = _mantissaTable[_offsetTable[value.Raw >> 10] + (((uint)value.Raw) & 0x03FF)] + _exponentTable[value.Raw >> 10]; return result.Single; } // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- /// /// Gets a value indicating whether this is the same as the second specified /// . /// /// The object to compare, if it is a . /// true, if both are the same. public override bool Equals(object obj) { if (!(obj is Half)) { return false; } Half half = (Half)obj; return Equals(half); } /// /// Gets a hash code as an indication for object equality. /// /// The hash code. public override int GetHashCode() { return Raw; } /// /// Gets a string describing this . /// /// A string describing this . public override string ToString() { return ((double)this).ToString(); } /// /// Indicates whether the current is equal to another . /// /// A to compare with this . /// true if the current is equal to the other parameter; otherwise, false. /// public bool Equals(Half other) { return Equals(Raw == other.Raw); } /* /// /// Returns a value indicating whether the specified number evaluates to not a number (). /// /// A half-precision floating-point number. /// true if value evaluates to not a number (); otherwise false. public static bool IsNaN(Half half) { return (half.Raw & 0x7FFF) > PositiveInfinity.Raw; } /// /// Returns a value indicating whether the specified number evaluates to negative or positive infinity. /// /// A half-precision floating-point number. /// true if half evaluates to or ; /// otherwise false. public static bool IsInfinity(Half half) { return (half.Raw & 0x7FFF) == PositiveInfinity.Raw; } /// /// Returns a value indicating whether the specified number evaluates to negative infinity. /// /// A half-precision floating-point number. /// true if half evaluates to ; otherwise false. public static bool IsNegativeInfinity(Half half) { return half.Raw == NegativeInfinity.Raw; } /// /// Returns a value indicating whether the specified number evaluates to positive infinity. /// /// A half-precision floating-point number. /// true if half evaluates to ; otherwise false. public static bool IsPositiveInfinity(Half half) { return half.Raw == PositiveInfinity.Raw; }*/ } }