/* * compute X = (a * X + c) MOD m where c = a */ void m_apm_get_random(M_APM mrnd) { if (M_firsttime2) /* use the system time as the initial seed value */ { M_firsttime2 = FALSE; M_rnd_aa = m_apm_init(); M_rnd_XX = m_apm_init(); M_rnd_mm = m_apm_init(); M_rtmp0 = m_apm_init(); M_rtmp1 = m_apm_init(); /* set the multiplier M_rnd_aa and M_rnd_mm */ m_apm_set_string(M_rnd_aa, "716805947629621"); m_apm_set_string(M_rnd_mm, "1.0E15"); M_get_rnd_seed(M_rnd_XX); } m_apm_multiply(M_rtmp0, M_rnd_XX, M_rnd_aa); m_apm_add(M_rtmp1, M_rtmp0, M_rnd_aa); m_apm_integer_div_rem(M_rtmp0, M_rnd_XX, M_rtmp1, M_rnd_mm); m_apm_copy(mrnd, M_rnd_XX); mrnd->m_apm_exponent -= 15; }
static M_APM Bnew(lua_State *L) { M_APM x=m_apm_init(); lua_boxpointer(L,x); luaL_setmetatable(L,MYTYPE); return x; }
M_APM m_apm_init_mt(void) { M_APM t; m_apm_enter(); t=m_apm_init(); m_apm_leave(); return(t); }
void m_apm_cpp_precision(int digits) { if (MM_lc_PI_digits == 0) { m_apm_free(m_apm_init()); } if (digits >= 2) MM_cpp_min_precision = digits; else MM_cpp_min_precision = 2; }
void init_working_mapm() { M_limit = m_apm_init(); M_digit = m_apm_init(); M_quot = m_apm_init(); M_rem = m_apm_init(); M_tmp0 = m_apm_init(); M_tmp1 = m_apm_init(); }
M_APM apm_get(struct DeltaVariable *v) { M_APM r = m_apm_init(); if(v->type == DELTA_TYPE_NUMBER) m_apm_set_double(r, delta_cast_number(v)); else { int release; struct DeltaVariable *arg = delta_cast_string(v, &release); if(release) m_apm_set_string(r, arg->value.ptr); else m_apm_set_string(r, delta_copy_string(arg->value.ptr)); } return r; }
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); }
int main(int argc, char *argv[]) { char version_info[80]; int ct; /* declare the M_APM variables ... */ M_APM aa_mapm; M_APM bb_mapm; M_APM cc_mapm; M_APM dd_mapm; if (argc < 2) { m_apm_lib_short_version(version_info); fprintf(stdout, "Usage: primenum number\t\t\t[Version 1.3, MAPM Version %s]\n", version_info); fprintf(stdout, " find the first 10 prime numbers starting with \'number\'\n"); exit(4); } /* now initialize the M_APM variables ... */ aa_mapm = m_apm_init(); bb_mapm = m_apm_init(); cc_mapm = m_apm_init(); dd_mapm = m_apm_init(); init_working_mapm(); m_apm_set_string(dd_mapm, argv[1]); /* * if input < 3, set start point = 3 */ if (m_apm_compare(dd_mapm, MM_Three) == -1) { m_apm_copy(dd_mapm, MM_Three); } /* * make sure we start with an odd integer */ m_apm_integer_divide(aa_mapm, dd_mapm, MM_Two); m_apm_multiply(bb_mapm, MM_Two, aa_mapm); m_apm_add(aa_mapm, MM_One, bb_mapm); ct = 0; while (TRUE) { if (is_number_prime(aa_mapm)) { m_apm_to_integer_string(buffer, aa_mapm); fprintf(stdout,"%s\n",buffer); if (++ct == 10) break; } m_apm_add(cc_mapm, MM_Two, aa_mapm); m_apm_copy(aa_mapm, cc_mapm); } free_working_mapm(); m_apm_free(aa_mapm); m_apm_free(bb_mapm); m_apm_free(cc_mapm); m_apm_free(dd_mapm); m_apm_free_all_mem(); exit(0); }
void m_apm_exp(M_APM r, int places, M_APM x) { M_APM tmp7, tmp8, tmp9; int dplaces, nn, ii; if (MM_firsttime1) { MM_firsttime1 = FALSE; MM_exp_log2R = m_apm_init(); MM_exp_512R = m_apm_init(); m_apm_set_string(MM_exp_log2R, "1.44269504089"); /* ~ 1 / log(2) */ m_apm_set_string(MM_exp_512R, "1.953125E-3"); /* 1 / 512 */ } tmp7 = M_get_stack_var(); tmp8 = M_get_stack_var(); tmp9 = M_get_stack_var(); if (x->m_apm_sign == 0) /* if input == 0, return '1' */ { m_apm_copy(r, MM_One); M_restore_stack(3); return; } if (x->m_apm_exponent <= -3) /* already small enough so call _raw directly */ { M_raw_exp(tmp9, (places + 6), x); m_apm_round(r, places, tmp9); M_restore_stack(3); return; } /* From David H. Bailey's MPFUN Fortran package : exp (t) = (1 + r + r^2 / 2! + r^3 / 3! + r^4 / 4! ...) ^ q * 2 ^ n where q = 256, r = t' / q, t' = t - n Log(2) and where n is chosen so that -0.5 Log(2) < t' <= 0.5 Log(2). Reducing t mod Log(2) and dividing by 256 insures that -0.001 < r <= 0.001, which accelerates convergence in the above series. I use q = 512 and also limit how small 'r' can become. The 'r' used here is limited in magnitude from 1.95E-4 < |r| < 1.35E-3. Forcing 'r' into a narrow range keeps the algorithm 'well behaved'. ( the range is [0.1 / 512] to [log(2) / 512] ) */ if (M_exp_compute_nn(&nn, tmp7, x) != 0) { M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_exp\', Input too large, Overflow"); M_set_to_zero(r); M_restore_stack(3); return; } dplaces = places + 8; /* check to make sure our log(2) is accurate enough */ M_check_log_places(dplaces); m_apm_multiply(tmp8, tmp7, MM_lc_log2); m_apm_subtract(tmp7, x, tmp8); /* * guarantee that |tmp7| is between 0.1 and 0.9999999.... * (in practice, the upper limit only reaches log(2), 0.693... ) */ while (TRUE) { if (tmp7->m_apm_sign != 0) { if (tmp7->m_apm_exponent == 0) break; } if (tmp7->m_apm_sign >= 0) { nn++; m_apm_subtract(tmp8, tmp7, MM_lc_log2); m_apm_copy(tmp7, tmp8); } else { nn--; m_apm_add(tmp8, tmp7, MM_lc_log2); m_apm_copy(tmp7, tmp8); } } m_apm_multiply(tmp9, tmp7, MM_exp_512R); /* perform the series expansion ... */ M_raw_exp(tmp8, dplaces, tmp9); /* * raise result to the 512 power * * note : x ^ 512 = (((x ^ 2) ^ 2) ^ 2) ... 9 times */ ii = 9; while (TRUE) { m_apm_multiply(tmp9, tmp8, tmp8); m_apm_round(tmp8, dplaces, tmp9); if (--ii == 0) break; } /* now compute 2 ^ N */ m_apm_integer_pow(tmp7, dplaces, MM_Two, nn); m_apm_multiply(tmp9, tmp7, tmp8); m_apm_round(r, places, tmp9); M_restore_stack(3); /* restore the 3 locals we used here */ }
void m_apm_add(M_APM r, M_APM a, M_APM b) { int j, carry, sign, aexp, bexp, adigits, bdigits; if (M_add_firsttime) { M_add_firsttime = FALSE; M_work1 = m_apm_init(); M_work2 = m_apm_init(); } if (a->m_apm_sign == 0) { m_apm_copy(r,b); return; } if (b->m_apm_sign == 0) { m_apm_copy(r,a); return; } if (a->m_apm_sign == 1 && b->m_apm_sign == -1) { b->m_apm_sign = 1; m_apm_subtract(r,a,b); b->m_apm_sign = -1; return; } if (a->m_apm_sign == -1 && b->m_apm_sign == 1) { a->m_apm_sign = 1; m_apm_subtract(r,b,a); a->m_apm_sign = -1; return; } sign = a->m_apm_sign; /* signs are the same, result will be same */ aexp = a->m_apm_exponent; bexp = b->m_apm_exponent; m_apm_copy(M_work1, a); m_apm_copy(M_work2, b); /* * scale by at least 1 factor of 10 in case the MSB carrys */ if (aexp == bexp) { M_apm_scale(M_work1, 2); /* shift 2 digits == 1 byte for efficiency */ M_apm_scale(M_work2, 2); } else { if (aexp > bexp) { M_apm_scale(M_work1, 2); M_apm_scale(M_work2, (aexp + 2 - bexp)); } else /* aexp < bexp */ { M_apm_scale(M_work2, 2); M_apm_scale(M_work1, (bexp + 2 - aexp)); } } adigits = M_work1->m_apm_datalength; bdigits = M_work2->m_apm_datalength; if (adigits >= bdigits) { m_apm_copy(r, M_work1); j = (bdigits + 1) >> 1; carry = 0; while (TRUE) { j--; r->m_apm_data[j] += carry + M_work2->m_apm_data[j]; if (r->m_apm_data[j] >= 100) { r->m_apm_data[j] -= 100; carry = 1; } else carry = 0; if (j == 0) break; } }
void m_apm_trim_mem_usage() { m_apm_free_all_mem(); m_apm_free(m_apm_init()); }
void m_apm_factorial(M_APM moutput, M_APM minput) { int ii, nmul, ndigits, nd, jj, kk, mm, ct; M_APM array[NDIM]; M_APM iprod1, iprod2, tmp1, tmp2; /* return 1 for any input <= 1 */ if (m_apm_compare(minput, MM_One) <= 0) { m_apm_copy(moutput, MM_One); return; } ct = 0; mm = NDIM - 2; ndigits = 256; nd = ndigits - 20; tmp1 = m_apm_init(); tmp2 = m_apm_init(); iprod1 = m_apm_init(); iprod2 = m_apm_init(); array[0] = m_apm_init(); m_apm_copy(tmp2, minput); /* loop until multiply count-down has reached '2' */ while (TRUE) { m_apm_copy(iprod1, MM_One); /* * loop until the number of significant digits in this * partial result is slightly less than 256 */ while (TRUE) { m_apm_multiply(iprod2, iprod1, tmp2); m_apm_subtract(tmp1, tmp2, MM_One); m_apm_multiply(iprod1, iprod2, tmp1); /* * I know, I know. There just isn't a *clean* way * to break out of 2 nested loops. */ if (m_apm_compare(tmp1, MM_Two) <= 0) goto PHASE2; m_apm_subtract(tmp2, tmp1, MM_One); if (iprod1->m_apm_datalength > nd) break; } if (ct == (NDIM - 1)) { /* * if the array has filled up, start multiplying * some of the partial products now. */ m_apm_copy(tmp1, array[mm]); m_apm_multiply(array[mm], iprod1, tmp1); if (mm == 0) { mm = NDIM - 2; ndigits = ndigits << 1; nd = ndigits - 20; } else mm--; } else { /* * store this partial product in the array * and allocate the next array element */ m_apm_copy(array[ct], iprod1); array[++ct] = m_apm_init(); } } PHASE2: m_apm_copy(array[ct], iprod1); kk = ct; while (kk != 0) { ii = 0; jj = 0; nmul = (kk + 1) >> 1; while (TRUE) { /* must use tmp var when ii,jj point to same element */ if (ii == 0) { m_apm_copy(tmp1, array[ii]); m_apm_multiply(array[jj], tmp1, array[ii+1]); } else m_apm_multiply(array[jj], array[ii], array[ii+1]); if (++jj == nmul) break; ii += 2; } if ((kk & 1) == 0) { jj = kk >> 1; m_apm_copy(array[jj], array[kk]); } kk = kk >> 1; }
void M_apm_sdivide(M_APM r, int places, M_APM a, M_APM b) { int j, k, m, b0, sign, nexp, indexr, icompare, iterations; long trial_numer; void *vp; if (M_div_firsttime) { M_div_firsttime = FALSE; M_div_worka = m_apm_init(); M_div_workb = m_apm_init(); M_div_tmp7 = m_apm_init(); M_div_tmp8 = m_apm_init(); M_div_tmp9 = m_apm_init(); } sign = a->m_apm_sign * b->m_apm_sign; if (sign == 0) /* one number is zero, result is zero */ { if (b->m_apm_sign == 0) { M_apm_log_error_msg(M_APM_RETURN, "\'M_apm_sdivide\', Divide by 0"); } M_set_to_zero(r); return; } /* * Knuth step D1. Since base = 100, base / 2 = 50. * (also make the working copies positive) */ if (b->m_apm_data[0] >= 50) { m_apm_absolute_value(M_div_worka, a); m_apm_absolute_value(M_div_workb, b); } else /* 'normal' step D1 */ { k = 100 / (b->m_apm_data[0] + 1); m_apm_set_long(M_div_tmp9, (long)k); m_apm_multiply(M_div_worka, M_div_tmp9, a); m_apm_multiply(M_div_workb, M_div_tmp9, b); M_div_worka->m_apm_sign = 1; M_div_workb->m_apm_sign = 1; } /* setup trial denominator for step D3 */ b0 = 100 * (int)M_div_workb->m_apm_data[0]; if (M_div_workb->m_apm_datalength >= 3) b0 += M_div_workb->m_apm_data[1]; nexp = M_div_worka->m_apm_exponent - M_div_workb->m_apm_exponent; if (nexp > 0) iterations = nexp + places + 1; else iterations = places + 1; k = (iterations + 1) >> 1; /* required size of result, in bytes */ if (k > r->m_apm_malloclength) { if ((vp = MAPM_REALLOC(r->m_apm_data, (k + 32))) == NULL) { /* fatal, this does not return */ M_apm_log_error_msg(M_APM_FATAL, "\'M_apm_sdivide\', Out of memory"); } r->m_apm_malloclength = k + 28; r->m_apm_data = (UCHAR *)vp; } /* clear the exponent in the working copies */ M_div_worka->m_apm_exponent = 0; M_div_workb->m_apm_exponent = 0; /* if numbers are equal, ratio == 1.00000... */ if ((icompare = m_apm_compare(M_div_worka, M_div_workb)) == 0) { iterations = 1; r->m_apm_data[0] = 10; nexp++; } else /* ratio not 1, do the real division */ { if (icompare == 1) /* numerator > denominator */ { nexp++; /* to adjust the final exponent */ M_div_worka->m_apm_exponent += 1; /* multiply numerator by 10 */ } else /* numerator < denominator */ { M_div_worka->m_apm_exponent += 2; /* multiply numerator by 100 */ } indexr = 0; m = 0; while (TRUE) { /* * Knuth step D3. Only use the 3rd -> 6th digits if the number * actually has that many digits. */ trial_numer = 10000L * (long)M_div_worka->m_apm_data[0]; if (M_div_worka->m_apm_datalength >= 5) { trial_numer += 100 * M_div_worka->m_apm_data[1] + M_div_worka->m_apm_data[2]; } else { if (M_div_worka->m_apm_datalength >= 3) trial_numer += 100 * M_div_worka->m_apm_data[1]; } j = (int)(trial_numer / b0); /* * Since the library 'normalizes' all the results, we need * to look at the exponent of the number to decide if we * have a lead in 0n or 00. */ if ((k = 2 - M_div_worka->m_apm_exponent) > 0) { while (TRUE) { j /= 10; if (--k == 0) break; } } if (j == 100) /* qhat == base ?? */ j = 99; /* if so, decrease by 1 */ m_apm_set_long(M_div_tmp8, (long)j); m_apm_multiply(M_div_tmp7, M_div_tmp8, M_div_workb); /* * Compare our q-hat (j) against the desired number. * j is either correct, 1 too large, or 2 too large * per Theorem B on pg 272 of Art of Compter Programming, * Volume 2, 3rd Edition. * * The above statement is only true if using the 2 leading * digits of the numerator and the leading digit of the * denominator. Since we are using the (3) leading digits * of the numerator and the (2) leading digits of the * denominator, we eliminate the case where our q-hat is * 2 too large, (and q-hat being 1 too large is quite remote). */ if (m_apm_compare(M_div_tmp7, M_div_worka) == 1) { j--; m_apm_subtract(M_div_tmp8, M_div_tmp7, M_div_workb); m_apm_copy(M_div_tmp7, M_div_tmp8); } /* * Since we know q-hat is correct, step D6 is unnecessary. * * Store q-hat, step D5. Since D6 is unnecessary, we can * do D5 before D4 and decide if we are done. */ r->m_apm_data[indexr++] = (UCHAR)j; /* j == 'qhat' */ m += 2; if (m >= iterations) break; /* step D4 */ m_apm_subtract(M_div_tmp9, M_div_worka, M_div_tmp7); /* * if the subtraction yields zero, the division is exact * and we are done early. */ if (M_div_tmp9->m_apm_sign == 0) { iterations = m; break; } /* multiply by 100 and re-save */ M_div_tmp9->m_apm_exponent += 2; m_apm_copy(M_div_worka, M_div_tmp9); } } r->m_apm_sign = sign; r->m_apm_exponent = nexp; r->m_apm_datalength = iterations; M_apm_normalize(r); }
void M_init_trig_globals() { MM_lc_PI_digits = VALID_DECIMAL_PLACES; MM_lc_log_digits = VALID_DECIMAL_PLACES; MM_cpp_min_precision = 30; MM_Zero = m_apm_init(); MM_One = m_apm_init(); MM_Two = m_apm_init(); MM_Three = m_apm_init(); MM_Four = m_apm_init(); MM_Five = m_apm_init(); MM_Ten = m_apm_init(); MM_0_5 = m_apm_init(); MM_LOG_2_BASE_E = m_apm_init(); MM_LOG_3_BASE_E = m_apm_init(); MM_E = m_apm_init(); MM_PI = m_apm_init(); MM_HALF_PI = m_apm_init(); MM_2_PI = m_apm_init(); MM_lc_PI = m_apm_init(); MM_lc_HALF_PI = m_apm_init(); MM_lc_2_PI = m_apm_init(); MM_lc_log2 = m_apm_init(); MM_lc_log10 = m_apm_init(); MM_lc_log10R = m_apm_init(); MM_0_85 = m_apm_init(); MM_5x_125R = m_apm_init(); MM_5x_64R = m_apm_init(); MM_5x_256R = m_apm_init(); MM_5x_Eight = m_apm_init(); MM_5x_Sixteen = m_apm_init(); MM_5x_Twenty = m_apm_init(); MM_LOG_E_BASE_10 = m_apm_init(); MM_LOG_10_BASE_E = m_apm_init(); m_apm_set_string(MM_One, "1"); m_apm_set_string(MM_Two, "2"); m_apm_set_string(MM_Three, "3"); m_apm_set_string(MM_Four, "4"); m_apm_set_string(MM_Five, "5"); m_apm_set_string(MM_Ten, "10"); m_apm_set_string(MM_0_5, "0.5"); m_apm_set_string(MM_0_85, "0.85"); m_apm_set_string(MM_5x_125R, "8.0E-3"); m_apm_set_string(MM_5x_64R, "1.5625E-2"); m_apm_set_string(MM_5x_256R, "3.90625E-3"); m_apm_set_string(MM_5x_Eight, "8"); m_apm_set_string(MM_5x_Sixteen, "16"); m_apm_set_string(MM_5x_Twenty, "20"); m_apm_set_string(MM_LOG_2_BASE_E, MM_cnst_log_2); m_apm_set_string(MM_LOG_3_BASE_E, MM_cnst_log_3); m_apm_set_string(MM_LOG_10_BASE_E, MM_cnst_log_10); m_apm_set_string(MM_LOG_E_BASE_10, MM_cnst_1_log_10); m_apm_set_string(MM_lc_log2, MM_cnst_log_2); m_apm_set_string(MM_lc_log10, MM_cnst_log_10); m_apm_set_string(MM_lc_log10R, MM_cnst_1_log_10); m_apm_set_string(MM_E, MM_cnst_E); m_apm_set_string(MM_PI, MM_cnst_PI); m_apm_multiply(MM_HALF_PI, MM_PI, MM_0_5); m_apm_multiply(MM_2_PI, MM_PI, MM_Two); m_apm_copy(MM_lc_PI, MM_PI); m_apm_copy(MM_lc_HALF_PI, MM_HALF_PI); m_apm_copy(MM_lc_2_PI, MM_2_PI); }
/* 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 */ }