Created
November 29, 2018 05:39
-
-
Save otmb/a3ede7130031458c0cc98f6428573d1f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
// https://www.csharpcodi.com/vs2/1607/MBINCompiler/MBINCompiler/HalfHelper.cs/ | |
public static class HalfHelper | |
{ | |
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(); | |
// Transforms the subnormal representation to a normalized one. | |
private static uint ConvertMantissa(int i) | |
{ | |
uint m = (uint)(i << 13); // Zero pad mantissa bits | |
uint e = 0; // Zero exponent | |
// While not normalized | |
while ((m & 0x00800000) == 0) | |
{ | |
e -= 0x00800000; // Decrement exponent (1<<23) | |
m <<= 1; // Shift mantissa | |
} | |
m &= unchecked((uint)~0x00800000); // Clear leading 1 bit | |
e += 0x38800000; // Adjust bias ((127-14)<<23) | |
return m | e; // Return combined number | |
} | |
private static uint[] GenerateMantissaTable() | |
{ | |
uint[] mantissaTable = new uint[2048]; | |
mantissaTable[0] = 0; | |
for (int i = 1; i < 1024; i++) | |
{ | |
mantissaTable[i] = ConvertMantissa(i); | |
} | |
for (int i = 1024; i < 2048; i++) | |
{ | |
mantissaTable[i] = (uint)(0x38000000 + ((i - 1024) << 13)); | |
} | |
return mantissaTable; | |
} | |
private static uint[] GenerateExponentTable() | |
{ | |
uint[] exponentTable = new uint[64]; | |
exponentTable[0] = 0; | |
for (int i = 1; i < 31; i++) | |
{ | |
exponentTable[i] = (uint)(i << 23); | |
} | |
exponentTable[31] = 0x47800000; | |
exponentTable[32] = 0x80000000; | |
for (int i = 33; i < 63; i++) | |
{ | |
exponentTable[i] = (uint)(0x80000000 + ((i - 32) << 23)); | |
} | |
exponentTable[63] = 0xc7800000; | |
return exponentTable; | |
} | |
private static ushort[] GenerateOffsetTable() | |
{ | |
ushort[] offsetTable = new ushort[64]; | |
offsetTable[0] = 0; | |
for (int i = 1; i < 32; i++) | |
{ | |
offsetTable[i] = 1024; | |
} | |
offsetTable[32] = 0; | |
for (int i = 33; i < 64; i++) | |
{ | |
offsetTable[i] = 1024; | |
} | |
return offsetTable; | |
} | |
private static ushort[] GenerateBaseTable() | |
{ | |
ushort[] baseTable = new ushort[512]; | |
for (int i = 0; i < 256; ++i) | |
{ | |
sbyte e = (sbyte)(127 - i); | |
if (e > 24) | |
{ // Very small numbers map to zero | |
baseTable[i | 0x000] = 0x0000; | |
baseTable[i | 0x100] = 0x8000; | |
} | |
else if (e > 14) | |
{ // Small numbers map to denorms | |
baseTable[i | 0x000] = (ushort)(0x0400 >> (18 + e)); | |
baseTable[i | 0x100] = (ushort)((0x0400 >> (18 + e)) | 0x8000); | |
} | |
else if (e >= -15) | |
{ // Normal numbers just lose precision | |
baseTable[i | 0x000] = (ushort)((15 - e) << 10); | |
baseTable[i | 0x100] = (ushort)(((15 - e) << 10) | 0x8000); | |
} | |
else if (e > -128) | |
{ // Large numbers map to Infinity | |
baseTable[i | 0x000] = 0x7c00; | |
baseTable[i | 0x100] = 0xfc00; | |
} | |
else | |
{ // Infinity and NaN's stay Infinity and NaN's | |
baseTable[i | 0x000] = 0x7c00; | |
baseTable[i | 0x100] = 0xfc00; | |
} | |
} | |
return baseTable; | |
} | |
private static sbyte[] GenerateShiftTable() | |
{ | |
sbyte[] shiftTable = new sbyte[512]; | |
for (int i = 0; i < 256; ++i) | |
{ | |
sbyte e = (sbyte)(127 - i); | |
if (e > 24) | |
{ // Very small numbers map to zero | |
shiftTable[i | 0x000] = 24; | |
shiftTable[i | 0x100] = 24; | |
} | |
else if (e > 14) | |
{ // Small numbers map to denorms | |
shiftTable[i | 0x000] = (sbyte)(e - 1); | |
shiftTable[i | 0x100] = (sbyte)(e - 1); | |
} | |
else if (e >= -15) | |
{ // Normal numbers just lose precision | |
shiftTable[i | 0x000] = 13; | |
shiftTable[i | 0x100] = 13; | |
} | |
else if (e > -128) | |
{ // Large numbers map to Infinity | |
shiftTable[i | 0x000] = 24; | |
shiftTable[i | 0x100] = 24; | |
} | |
else | |
{ // Infinity and NaN's stay Infinity and NaN's | |
shiftTable[i | 0x000] = 13; | |
shiftTable[i | 0x100] = 13; | |
} | |
} | |
return shiftTable; | |
} | |
public static float HalfToSingle(ushort half) | |
{ | |
uint result = mantissaTable[offsetTable[half >> 10] + (half & 0x3ff)] + exponentTable[half >> 10]; | |
return System.BitConverter.ToSingle( System.BitConverter.GetBytes( result ), 0 ); | |
//return *((float*)&result); | |
} | |
public static ushort SingleToHalf(float single) | |
{ | |
//uint value = *((uint*)&single); | |
uint value = System.BitConverter.ToUInt32( System.BitConverter.GetBytes( single ), 0 ); | |
ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23])); | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment