Created
July 2, 2018 00:12
-
-
Save catid/893b4d96e20b6c03c6ce8424f2ac03ea to your computer and use it in GitHub Desktop.
Lossy integer compression 32 => 16 bits, 16 => 8 bits
This file contains hidden or 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
//------------------------------------------------------------------------------ | |
// Intrinsics | |
/// Returns first position with set bit (LSB = 0) | |
/// Precondition: x != 0 | |
TONK_FORCE_INLINE unsigned NonzeroLowestBitIndex(uint32_t x) | |
{ | |
#ifdef _MSC_VER | |
unsigned long index; | |
// Note: Ignoring result because x != 0 | |
_BitScanReverse(&index, x); | |
return (unsigned)index; | |
#else | |
// Note: Ignoring return value of 0 because x != 0 | |
return 31 - (unsigned)__builtin_clz(x); | |
#endif | |
} | |
//------------------------------------------------------------------------------ | |
// Serializers | |
/// Represent a 32-bit integer with 16 bits using fixed point. | |
/// 5 bits of exponent, representing offsets of 0..20. | |
/// 11 bits of mantissa, providing a precision of 1/2048 = 0.048828125%. | |
/// The return value will decompress within 0.1% of the input word | |
TONK_FORCE_INLINE uint16_t FixedPointCompress32to16(uint32_t word) | |
{ | |
if (word == 0) { | |
return 0; | |
} | |
const unsigned nonzeroBits = NonzeroLowestBitIndex(word) + 1; | |
TONK_DEBUG_ASSERT(nonzeroBits >= 1 && nonzeroBits <= 32); | |
if (nonzeroBits <= 11) { | |
TONK_DEBUG_ASSERT(word < 2048); | |
return (uint16_t)word; | |
} | |
const unsigned shift = nonzeroBits - 11; | |
TONK_DEBUG_ASSERT(shift < 32); | |
TONK_DEBUG_ASSERT((word >> shift) < 2048); | |
return (uint16_t)((word >> shift) | (shift << 11)); | |
} | |
TONK_FORCE_INLINE uint32_t FixedPointDecompress16to32(uint16_t fpword) | |
{ | |
return (uint32_t)(((uint32_t)fpword & 2047) << ((uint32_t)fpword >> 11)); | |
} | |
/// Represent a 16-bit integer with 8 bits using fixed point. | |
/// 4 bits of exponent, representing offsets of 0..15. | |
/// 4 bits of mantissa, providing a precision of 1/16 = 6.25%. | |
/// The return value will decompress within 13% of the input word | |
TONK_FORCE_INLINE uint8_t FixedPointCompress16to8(uint16_t word) | |
{ | |
if (word == 0) { | |
return 0; | |
} | |
const unsigned nonzeroBits = NonzeroLowestBitIndex(word) + 1; | |
TONK_DEBUG_ASSERT(nonzeroBits >= 1 && nonzeroBits <= 16); | |
if (nonzeroBits <= 4) { | |
TONK_DEBUG_ASSERT(word < 16); | |
return (uint8_t)word; | |
} | |
const unsigned shift = nonzeroBits - 4; | |
TONK_DEBUG_ASSERT(shift < 16); | |
TONK_DEBUG_ASSERT((word >> shift) < 16); | |
return (uint8_t)((word >> shift) | (shift << 4)); | |
} | |
TONK_FORCE_INLINE uint16_t FixedPointDecompress8to16(uint8_t fpword) | |
{ | |
return (uint16_t)(((uint16_t)fpword & 15) << ((uint16_t)fpword >> 4)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment