Ejemplo n.º 1
0
void	M_fast_mul_fft(UCHAR *ww, UCHAR *uu, UCHAR *vv, int nbytes)
{
int             mflag, i, j, nn2, nn;
double          carry, nnr, dtemp, *a, *b;
UCHAR           *w0;
unsigned long   ul;

if (M_size < 0)                  /* if first time in, setup working arrays */
  {
   if (M_get_sizeof_int() == 2)  /* if still using 16 bit compilers */
     M_size = 1030;
   else
     M_size = 8200;

   M_aa_array = (double *)MAPM_MALLOC(M_size * sizeof(double));
   M_bb_array = (double *)MAPM_MALLOC(M_size * sizeof(double));
   
   if ((M_aa_array == NULL) || (M_bb_array == NULL))
     {
      /* fatal, this does not return */

      M_apm_log_error_msg(M_APM_EXIT, "\'M_fast_mul_fft\', Out of memory");
     }
  }

nn  = nbytes;
nn2 = nbytes >> 1;

if (nn > M_size)
  {
   mflag = TRUE;

   a = (double *)MAPM_MALLOC((nn + 8) * sizeof(double));
   b = (double *)MAPM_MALLOC((nn + 8) * sizeof(double));
   
   if ((a == NULL) || (b == NULL))
     {
      /* fatal, this does not return */

      M_apm_log_error_msg(M_APM_EXIT, "\'M_fast_mul_fft\', Out of memory");
     }
  }
else
  {
   mflag = FALSE;

   a = M_aa_array;
   b = M_bb_array;
  }

/*
 *   convert normal base 100 MAPM numbers to base 10000
 *   for the FFT operation.
 */

i = 0;
for (j=0; j < nn2; j++)
  {
   a[j] = (double)((int)uu[i] * 100 + uu[i+1]);
   b[j] = (double)((int)vv[i] * 100 + vv[i+1]);
   i += 2;
  }

/* zero fill the second half of the arrays */

for (j=nn2; j < nn; j++)
  {
   a[j] = 0.0;
   b[j] = 0.0;
  }

/* perform the forward Fourier transforms for both numbers */

M_rdft(nn, 1, a);
M_rdft(nn, 1, b);

/* perform the convolution ... */

b[0] *= a[0];
b[1] *= a[1];

for (j=3; j <= nn; j += 2)
  {
   dtemp  = b[j-1];
   b[j-1] = dtemp * a[j-1] - b[j] * a[j];
   b[j]   = dtemp * a[j] + b[j] * a[j-1];
  }

/* perform the inverse transform on the result */

M_rdft(nn, -1, b);

/* perform a final pass to release all the carries */
/* we are still in base 10000 at this point        */

carry = 0.0;
j     = nn;
nnr   = 2.0 / (double)nn;

while (1)
  {
   dtemp = b[--j] * nnr + carry + 0.5;
   ul    = (unsigned long)(dtemp * 1.0E-4);
   carry = (double)ul;
   b[j]  = dtemp - carry * 10000.0;

   if (j == 0)
     break;
  }

/* copy result to our destination after converting back to base 100 */

w0 = ww;
M_get_div_rem((int)ul, w0, (w0 + 1));

for (j=0; j <= (nn - 2); j++)
  {
   w0 += 2;
   M_get_div_rem((int)b[j], w0, (w0 + 1));
  }

if (mflag)
  {
   MAPM_FREE(b);
   MAPM_FREE(a);
  }
}
Ejemplo n.º 2
0
void	M_fast_multiply(M_APM rr, M_APM aa, M_APM bb)
{
void	*vp;
int	ii, k, nexp, sign;

if (M_firsttimef)
  {
   M_firsttimef = FALSE;

   for (k=0; k < M_STACK_SIZE; k++)
     mul_stack_data_size[k] = 0;

   size_flag = M_get_sizeof_int();
   bit_limit = 8 * size_flag + 1;

   M_ain = m_apm_init();
   M_bin = m_apm_init();
  }

exp_stack_ptr   = -1;
M_mul_stack_ptr = -1;

m_apm_copy(M_ain, aa);
m_apm_copy(M_bin, bb);

sign = M_ain->m_apm_sign * M_bin->m_apm_sign;
nexp = M_ain->m_apm_exponent + M_bin->m_apm_exponent;

if (M_ain->m_apm_datalength >= M_bin->m_apm_datalength)
  ii = M_ain->m_apm_datalength;
else
  ii = M_bin->m_apm_datalength;

ii = (ii + 1) >> 1;
ii = M_next_power_of_2(ii);

/* Note: 'ii' must be >= 4 here. this is guaranteed 
   by the caller: m_apm_multiply
*/

k = 2 * ii;                   /* required size of result, in bytes  */

M_apm_pad(M_ain, k);          /* fill out the data so the number of */
M_apm_pad(M_bin, k);          /* bytes is an exact power of 2       */

if (k > rr->m_apm_malloclength)
  {
   if ((vp = MAPM_REALLOC(rr->m_apm_data, (k + 32))) == NULL)
     {
      /* fatal, this does not return */

      M_apm_log_error_msg(M_APM_FATAL, "\'M_fast_multiply\', Out of memory");
     }
  
   rr->m_apm_malloclength = k + 28;
   rr->m_apm_data = (UCHAR *)vp;
  }

#ifdef NO_FFT_MULTIPLY

M_fmul_div_conq(rr->m_apm_data, M_ain->m_apm_data, 
                                M_bin->m_apm_data, ii);
#else

/*
 *     if the numbers are *really* big, use the divide-and-conquer
 *     routine first until the numbers are small enough to be handled 
 *     by the FFT algorithm. If the numbers are already small enough,
 *     call the FFT multiplication now.
 *
 *     Note that 'ii' here is (and must be) an exact power of 2.
 */

if (size_flag == 2)   /* if still using 16 bit compilers .... */
  {
   M_fast_mul_fft(rr->m_apm_data, M_ain->m_apm_data, 
                                  M_bin->m_apm_data, ii);
  }
else                  /* >= 32 bit compilers */
  {
   if (ii > (MAX_FFT_BYTES + 2))
     {
      M_fmul_div_conq(rr->m_apm_data, M_ain->m_apm_data, 
                                      M_bin->m_apm_data, ii);
     }
   else
     {
      M_fast_mul_fft(rr->m_apm_data, M_ain->m_apm_data, 
                                     M_bin->m_apm_data, ii);
     }
  }

#endif

rr->m_apm_sign       = sign;
rr->m_apm_exponent   = nexp;
rr->m_apm_datalength = 4 * ii;

M_apm_normalize(rr);
}
Ejemplo n.º 3
0
/*
	Calculate the POW function by calling EXP :

                  Y      A                 
                 X   =  e    where A = Y * log(X)
*/
void	m_apm_pow(M_APM rr, int places, M_APM xx, M_APM yy)
{
int	iflag, pflag;
char    sbuf[64];
M_APM   tmp8, tmp9;

/* if yy == 0, return 1 */

if (yy->m_apm_sign == 0)
  {
   m_apm_copy(rr, MM_One);
   return;
  }

/* if xx == 0, return 0 */

if (xx->m_apm_sign == 0)
  {
   M_set_to_zero(rr);
   return;
  }

if (M_size_flag == 0)       /* init locals on first call */
  {
   M_size_flag       = M_get_sizeof_int();
   M_last_log_digits = 0;
   M_last_xx_input   = m_apm_init();
   M_last_xx_log     = m_apm_init();
  }

/*
 *  if 'yy' is a small enough integer, call the more
 *  efficient _integer_pow function.
 */

if (m_apm_is_integer(yy))
  {
   iflag = FALSE;

   if (M_size_flag == 2)            /* 16 bit compilers */
     {
      if (yy->m_apm_exponent <= 4)
        iflag = TRUE;
     }
   else                             /* >= 32 bit compilers */
     {
      if (yy->m_apm_exponent <= 7)
        iflag = TRUE;
     }

   if (iflag)
     {
      m_apm_to_integer_string(sbuf, yy);
      m_apm_integer_pow(rr, places, xx, atoi(sbuf));
      return;
     }
  }

tmp8 = M_get_stack_var();
tmp9 = M_get_stack_var();

/*
 *    If parameter 'X' is the same this call as it 
 *    was the previous call, re-use the saved log 
 *    calculation from last time.
 */

pflag = FALSE;

if (M_last_log_digits >= places)
  {
   if (m_apm_compare(xx, M_last_xx_input) == 0)
     pflag = TRUE;
  }

if (pflag)
  {
   m_apm_round(tmp9, (places + 8), M_last_xx_log);
  }
else
  {
   m_apm_log(tmp9, (places + 8), xx);

   M_last_log_digits = places + 2;

   /* save the 'X' input value and the log calculation */

   m_apm_copy(M_last_xx_input, xx);
   m_apm_copy(M_last_xx_log, tmp9);
  }

m_apm_multiply(tmp8, tmp9, yy);
m_apm_exp(rr, places, tmp8);
M_restore_stack(2);                    /* restore the 2 locals we used here */
}