230 lines
4.8 KiB
C#
230 lines
4.8 KiB
C#
using System.Runtime.InteropServices;
|
|
|
|
namespace System
|
|
{
|
|
public static class HalfHelper
|
|
{
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
private struct UIntFloat
|
|
{
|
|
[FieldOffset(0)]
|
|
public uint UIntValue;
|
|
|
|
[FieldOffset(0)]
|
|
public float FloatValue;
|
|
}
|
|
|
|
private static uint[] mantissaTable = GenerateMantissaTable();
|
|
|
|
private static uint[] exponentTable = GenerateExponentTable();
|
|
|
|
private static ushort[] offsetTable = GenerateOffsetTable();
|
|
|
|
private static ushort[] baseTable = GenerateBaseTable();
|
|
|
|
private static sbyte[] shiftTable = GenerateShiftTable();
|
|
|
|
private static UIntFloat floatToIntConverter = new UIntFloat
|
|
{
|
|
FloatValue = 0f
|
|
};
|
|
|
|
private static uint FloatToUInt(float v)
|
|
{
|
|
floatToIntConverter.FloatValue = v;
|
|
return floatToIntConverter.UIntValue;
|
|
}
|
|
|
|
private static float UIntToFloat(uint v)
|
|
{
|
|
floatToIntConverter.UIntValue = v;
|
|
return floatToIntConverter.FloatValue;
|
|
}
|
|
|
|
private static uint ConvertMantissa(int i)
|
|
{
|
|
uint num = (uint)(i << 13);
|
|
uint num2 = 0u;
|
|
while ((num & 0x800000) == 0)
|
|
{
|
|
num2 -= 8388608;
|
|
num <<= 1;
|
|
}
|
|
num &= 0xFF7FFFFFu;
|
|
num2 += 947912704;
|
|
return num | num2;
|
|
}
|
|
|
|
private static uint[] GenerateMantissaTable()
|
|
{
|
|
uint[] array = new uint[2048];
|
|
array[0] = 0u;
|
|
for (int i = 1; i < 1024; i++)
|
|
{
|
|
array[i] = ConvertMantissa(i);
|
|
}
|
|
for (int j = 1024; j < 2048; j++)
|
|
{
|
|
array[j] = (uint)(939524096 + (j - 1024 << 13));
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private static uint[] GenerateExponentTable()
|
|
{
|
|
uint[] array = new uint[64];
|
|
array[0] = 0u;
|
|
for (int i = 1; i < 31; i++)
|
|
{
|
|
array[i] = (uint)(i << 23);
|
|
}
|
|
array[31] = 1199570944u;
|
|
array[32] = 2147483648u;
|
|
for (int j = 33; j < 63; j++)
|
|
{
|
|
array[j] = (uint)(2147483648u + (j - 32 << 23));
|
|
}
|
|
array[63] = 3347054592u;
|
|
return array;
|
|
}
|
|
|
|
private static ushort[] GenerateOffsetTable()
|
|
{
|
|
ushort[] array = new ushort[64];
|
|
array[0] = 0;
|
|
for (int i = 1; i < 32; i++)
|
|
{
|
|
array[i] = 1024;
|
|
}
|
|
array[32] = 0;
|
|
for (int j = 33; j < 64; j++)
|
|
{
|
|
array[j] = 1024;
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private static ushort[] GenerateBaseTable()
|
|
{
|
|
ushort[] array = new ushort[512];
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
sbyte b = (sbyte)(127 - i);
|
|
if (b > 24)
|
|
{
|
|
array[i | 0] = 0;
|
|
array[i | 0x100] = 32768;
|
|
}
|
|
else if (b > 14)
|
|
{
|
|
array[i | 0] = (ushort)(1024 >> 18 + b);
|
|
array[i | 0x100] = (ushort)((1024 >> 18 + b) | 0x8000);
|
|
}
|
|
else if (b >= -15)
|
|
{
|
|
array[i | 0] = (ushort)(15 - b << 10);
|
|
array[i | 0x100] = (ushort)((15 - b << 10) | 0x8000);
|
|
}
|
|
else if (b > sbyte.MinValue)
|
|
{
|
|
array[i | 0] = 31744;
|
|
array[i | 0x100] = 64512;
|
|
}
|
|
else
|
|
{
|
|
array[i | 0] = 31744;
|
|
array[i | 0x100] = 64512;
|
|
}
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private static sbyte[] GenerateShiftTable()
|
|
{
|
|
sbyte[] array = new sbyte[512];
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
sbyte b = (sbyte)(127 - i);
|
|
if (b > 24)
|
|
{
|
|
array[i | 0] = 24;
|
|
array[i | 0x100] = 24;
|
|
}
|
|
else if (b > 14)
|
|
{
|
|
array[i | 0] = (sbyte)(b - 1);
|
|
array[i | 0x100] = (sbyte)(b - 1);
|
|
}
|
|
else if (b >= -15)
|
|
{
|
|
array[i | 0] = 13;
|
|
array[i | 0x100] = 13;
|
|
}
|
|
else if (b > sbyte.MinValue)
|
|
{
|
|
array[i | 0] = 24;
|
|
array[i | 0x100] = 24;
|
|
}
|
|
else
|
|
{
|
|
array[i | 0] = 13;
|
|
array[i | 0x100] = 13;
|
|
}
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public static float HalfToSingle(Half half)
|
|
{
|
|
return UIntToFloat(mantissaTable[offsetTable[half.internalValue >> 10] + (half.internalValue & 0x3FF)] + exponentTable[half.internalValue >> 10]);
|
|
}
|
|
|
|
public static Half SingleToHalf(float single)
|
|
{
|
|
uint num = FloatToUInt(single);
|
|
return Half.ToHalf((ushort)(baseTable[(num >> 23) & 0x1FF] + ((num & 0x7FFFFF) >> (int)shiftTable[num >> 23])));
|
|
}
|
|
|
|
public static float Decompress(ushort compressedFloat)
|
|
{
|
|
return UIntToFloat(mantissaTable[offsetTable[compressedFloat >> 10] + (compressedFloat & 0x3FF)] + exponentTable[compressedFloat >> 10]);
|
|
}
|
|
|
|
public static ushort Compress(float uncompressedFloat)
|
|
{
|
|
uint num = FloatToUInt(uncompressedFloat);
|
|
return (ushort)(baseTable[(num >> 23) & 0x1FF] + ((num & 0x7FFFFF) >> (int)shiftTable[num >> 23]));
|
|
}
|
|
|
|
public static Half Negate(Half half)
|
|
{
|
|
return Half.ToHalf((ushort)(half.internalValue ^ 0x8000));
|
|
}
|
|
|
|
public static Half Abs(Half half)
|
|
{
|
|
return Half.ToHalf((ushort)(half.internalValue & 0x7FFF));
|
|
}
|
|
|
|
public static bool IsNaN(Half half)
|
|
{
|
|
return (half.internalValue & 0x7FFF) > 31744;
|
|
}
|
|
|
|
public static bool IsInfinity(Half half)
|
|
{
|
|
return (half.internalValue & 0x7FFF) == 31744;
|
|
}
|
|
|
|
public static bool IsPositiveInfinity(Half half)
|
|
{
|
|
return half.internalValue == 31744;
|
|
}
|
|
|
|
public static bool IsNegativeInfinity(Half half)
|
|
{
|
|
return half.internalValue == 64512;
|
|
}
|
|
}
|
|
}
|