Skip to content

Instantly share code, notes, and snippets.

@catid
Created July 2, 2018 00:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save catid/893b4d96e20b6c03c6ce8424f2ac03ea to your computer and use it in GitHub Desktop.
Save catid/893b4d96e20b6c03c6ce8424f2ac03ea to your computer and use it in GitHub Desktop.
Lossy integer compression 32 => 16 bits, 16 => 8 bits
//------------------------------------------------------------------------------
// 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