#include <windows.h>
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

static unsigned short log2_table[17];

void generate_log2_table (void)
{
  int i;
  for(i=0;i<16;i++)
    log2_table[i]=(unsigned short)(4096.0*log(1.0+(((double)i)/16.0))/log(2));
}

/* fflog2 works.
   IN : 16-bit integer
   OUT: 16-bit integer as a fixedpoint 4.12-bit integer now */
unsigned short fflog2 (unsigned short x)
{
  unsigned i = 15; /* integer part */
  unsigned j;          /* fractional part */
  
  if (!x)
    return 0;

  if (x < (1<<8)) {
    x <<= 8;
    i -= 8;
  } 
  if (x < (1<<12)) {
    x <<= 4;
    i -= 4;
  }
  if (x < (1<<14)) {
    x <<= 2;
    i -= 2;
  }
  if (x < (1<<15)) {
    x <<= 1;
    i -= 1;
  }

  x <<= 1;
  
  j = x >> 12;
  
  return /* integer part    */ (i<<12)
    |    /* fractional part */ (log2_table[j] + (((x & 0xfff) << 12) * (log2_table[j+1] - log2_table[j])));
}


/* fflog10 works */
unsigned short fflog10 (unsigned short x)
{
  return (fflog2(x) * (unsigned)(4096.0*(0.30102999566398119521373889472449/*log10(2)*/))) >> 12;
}

int
main (int argc, char *argv[])
{
  generate_log2_table();
  
  short test1 = (unsigned short)((1<<15)-1);
  short test2 = (unsigned short)((1<<14)+(1<<12)-1);
  short test3 = (unsigned short)((1<<14)+(1<<10));
  short test4 = (unsigned short)((1<<10)+(1<<8)-1);
  short test5 = (unsigned short)((1<<8)+(1<<3));
  short test6 = (unsigned short)((1<<6)+(1<<3));
  short test7 = (unsigned short)((1<<4)+(1<<1));
  short test8 = (unsigned short)((1<<4)-1);
  
  cout << "fflog10(" << test1 << ") = " << double(fflog10(test1)) / 4096.0 << endl;
  cout << "fflog10(" << test2 << ") = " << double(fflog10(test2)) / 4096.0 << endl;
  cout << "fflog10(" << test3 << ") = " << double(fflog10(test3)) / 4096.0 << endl;
  cout << "fflog10(" << test4 << ") = " << double(fflog10(test4)) / 4096.0 << endl;
  cout << "fflog10(" << test5 << ") = " << double(fflog10(test5)) / 4096.0 << endl;
  cout << "fflog10(" << test6 << ") = " << double(fflog10(test6)) / 4096.0 << endl;
  cout << "fflog10(" << test7 << ") = " << double(fflog10(test7)) / 4096.0 << endl;
  cout << "fflog10(" << test8 << ") = " << double(fflog10(test8)) / 4096.0 << endl;

  cout << "Press ENTER to continue..." << endl;
  getchar ();
  return 0;
}

#if 0

static unsigned short log10_table[17];

void generate_log10_table (void)
{
  int i;
  for(i=0;i<16;i++)
    log10_table[i]=(unsigned short)(4096.0*65536.0*log(1.0+(((double)i)/16.0))/log(10));
}

#define FFLOG10_2 4096.0*(0.30102999566398119521373889472449/*log10(2)*/)
unsigned short fflog10 (unsigned short x)
{
  unsigned i = (unsigned)(4096.0*4.5154499349597179282060834208674/*log10(2^15)*/);
  unsigned j;
  
  if (!x)
    return 0;

  if (x < (1<<8)) {
    x <<= 8;
    i -= (unsigned)(8.0*FFLOG10_2); /* 8 * log10(2) */
  } 
  if (x < (1<<12)) {
    x <<= 4;
    i -= (unsigned)(4.0*FFLOG10_2); /* 4 * log10(2) */
  }
  if (x < (1<<14)) {
    x <<= 2;
    i -= (unsigned)(2.0*FFLOG10_2); /* 2 * log10(2) */
  }
  if (x < (1<<15)) {
    x <<= 1;
    i -= (unsigned)(1.0*FFLOG10_2); /* 1 * log10(2) */
  }

  x <<= 1;

  j = x >> 12;
  
  return /* integer part    */ (i >> 16) 
    |    /* fractional part */ (log10_table[j] + (((x & 0xfff) << 12) * (log10_table[j+1] - log10_table[j])));
}
#endif

