#include <assert.h>
#include <math.h>
#include <stdio.h>

// wacky packed float

// pack a 22-bit integer into an 11-bit approximation

int convert22to11(int source22)
{
   int exp;

   assert(source22 >= 0 && source22 < (1 << 22));
   // we encode with 4 bits of exponent and 7 of mantissa

   // so exponent will encode a base value of:
   //    0:    0
   //    1:   (1 << 7)
   //    2:   (1 << 8)
   //   ...
   //   14:   (1 << 20)
   //   15:   (1 << 21)

   for (exp=15; exp > 0; --exp) {
      if (source22 >= 1 << (exp+6))
         break;
   }

   if (exp == 0) {
      return source22;
   }

   // shift source down so highest bit is 8th bit
   // ought to round here to minimize the error, but that would be messy

   source22 = source22 >> (exp-1);
   assert(source22 < (1 << 8) && source22 >= (1 << 7));
   source22 -= (1 << 7);

   return source22 + (exp << 7);
}

int convert11to22(int source11)
{
   int exp = (source11 >> 7);
   source11 &= (1 << 7)-1;

   if (exp == 0)
      return source11;

   source11 |= (1 << 7);
   return source11 << (exp-1);
}

int main(int argc, char **argv)
{
   int i,j,k, which;
   float worst=0, cur;
   for (i=0; i < (1 << 22); ++i) {
      //printf("%i\n", i);
      j = convert22to11(i);
      k = convert11to22(j);
      if (i == 0)
         assert(i == k);
      else {
         cur = (k - i) / (float) i;
         cur = (float) fabs(cur);
         if (cur > worst) {
            worst = cur;
            which = i;
         }
      }
   }
   printf("Worst error (%6.3f%%)\n", worst * 100);
   printf("%x encoded as %x decoded as %x\n", which, convert22to11(which), convert11to22(convert22to11(which)));
   return 0;
}
