void factrat(PRAT* px, uint32_t radix, int32_t precision) { PRAT fact = nullptr; PRAT frac = nullptr; PRAT neg_rat_one = nullptr; if (rat_gt(*px, rat_max_fact, precision) || rat_lt(*px, rat_min_fact, precision)) { // Don't attempt factorial of anything too large or small. throw CALC_E_OVERFLOW; } DUPRAT(fact, rat_one); DUPRAT(neg_rat_one, rat_one); neg_rat_one->pp->sign *= -1; DUPRAT(frac, *px); fracrat(&frac, radix, precision); // Check for negative integers and throw an error. if ((zerrat(frac) || (LOGRATRADIX(frac) <= -precision)) && (SIGN(*px) == -1)) { throw CALC_E_DOMAIN; } while (rat_gt(*px, rat_zero, precision) && (LOGRATRADIX(*px) > -precision)) { mulrat(&fact, *px, precision); subrat(px, rat_one, precision); } // Added to make numbers 'close enough' to integers use integer factorial. if (LOGRATRADIX(*px) <= -precision) { DUPRAT((*px), rat_zero); intrat(&fact, radix, precision); } while (rat_lt(*px, neg_rat_one, precision)) { addrat(px, rat_one, precision); divrat(&fact, *px, precision); } if (rat_neq(*px, rat_zero, precision)) { addrat(px, rat_one, precision); _gamma(px, radix, precision); mulrat(px, fact, precision); } else { DUPRAT(*px, fact); } destroyrat(fact); destroyrat(frac); destroyrat(neg_rat_one); }
void asinrat( PRAT *px, uint32_t radix, int32_t precision) { long sgn; PRAT pret= nullptr; PRAT phack= nullptr; sgn = (*px)->pp->sign* (*px)->pq->sign; (*px)->pp->sign = 1; (*px)->pq->sign = 1; // Avoid the really bad part of the asin curve near +/-1. DUPRAT(phack,*px); subrat(&phack, rat_one, precision); // Since *px might be epsilon near zero we must set it to zero. if ( rat_le(phack, rat_smallest, precision) && rat_ge(phack, rat_negsmallest, precision) ) { destroyrat(phack); DUPRAT( *px, pi_over_two ); } else { destroyrat(phack); if ( rat_gt( *px, pt_eight_five, precision) ) { if ( rat_gt( *px, rat_one, precision) ) { subrat( px, rat_one, precision); if ( rat_gt( *px, rat_smallest, precision) ) { throw( CALC_E_DOMAIN ); } else { DUPRAT(*px,rat_one); } } DUPRAT(pret,*px); mulrat( px, pret, precision); (*px)->pp->sign *= -1; addrat( px, rat_one, precision); rootrat( px, rat_two, radix, precision); _asinrat( px, precision); (*px)->pp->sign *= -1; addrat( px, pi_over_two, precision); destroyrat(pret); } else { _asinrat( px, precision); } } (*px)->pp->sign = sgn; (*px)->pq->sign = 1; }
void atanrat( PRAT *px, uint32_t radix, int32_t precision) { long sgn; PRAT tmpx= nullptr; sgn = (*px)->pp->sign * (*px)->pq->sign; (*px)->pp->sign = 1; (*px)->pq->sign = 1; if ( rat_gt( (*px), pt_eight_five, precision) ) { if ( rat_gt( (*px), rat_two, precision) ) { (*px)->pp->sign = sgn; (*px)->pq->sign = 1; DUPRAT(tmpx,rat_one); divrat(&tmpx, (*px), precision); _atanrat(&tmpx, precision); tmpx->pp->sign = sgn; tmpx->pq->sign = 1; DUPRAT(*px,pi_over_two); subrat(px, tmpx, precision); destroyrat( tmpx ); } else { (*px)->pp->sign = sgn; DUPRAT(tmpx,*px); mulrat( &tmpx, *px, precision); addrat( &tmpx, rat_one, precision); rootrat( &tmpx, rat_two, radix, precision); divrat( px, tmpx, precision); destroyrat( tmpx ); asinrat( px, radix, precision); (*px)->pp->sign = sgn; (*px)->pq->sign = 1; } } else { (*px)->pp->sign = sgn; (*px)->pq->sign = 1; _atanrat( px, precision); } if ( rat_gt( *px, pi_over_two, precision) ) { subrat( px, pi, precision); } }
void coshrat(PRAT* px, uint32_t radix, int32_t precision) { PRAT tmpx = nullptr; (*px)->pp->sign = 1; (*px)->pq->sign = 1; if (rat_ge(*px, rat_one, precision)) { DUPRAT(tmpx, *px); exprat(px, radix, precision); tmpx->pp->sign *= -1; exprat(&tmpx, radix, precision); addrat(px, tmpx, precision); divrat(px, rat_two, precision); destroyrat(tmpx); } else { _coshrat(px, radix, precision); } // Since *px might be epsilon below 1 due to TRIMIT // we need this trick here. if (rat_lt(*px, rat_one, precision)) { DUPRAT(*px, rat_one); } }
void tanhrat(PRAT* px, uint32_t radix, int32_t precision) { PRAT ptmp = nullptr; DUPRAT(ptmp, *px); sinhrat(px, radix, precision); coshrat(&ptmp, radix, precision); mulnumx(&((*px)->pp), ptmp->pq); mulnumx(&((*px)->pq), ptmp->pp); destroyrat(ptmp); }
bool IsValidForHypFunc(PRAT px, int32_t precision) { PRAT ptmp = nullptr; bool bRet = true; DUPRAT(ptmp, rat_min_exp); divrat(&ptmp, rat_ten, precision); if (rat_lt(px, ptmp, precision)) { bRet = false; } destroyrat(ptmp); return bRet; }
void sinhrat(PRAT* px, uint32_t radix, int32_t precision) { PRAT tmpx = nullptr; if (rat_ge(*px, rat_one, precision)) { DUPRAT(tmpx, *px); exprat(px, radix, precision); tmpx->pp->sign *= -1; exprat(&tmpx, radix, precision); subrat(px, tmpx, precision); divrat(px, rat_two, precision); destroyrat(tmpx); } else { _sinhrat(px, precision); } }
void _gamma( PRAT *pn, uint32_t radix, int32_t precision) { PRAT factorial= nullptr; PNUMBER count= nullptr; PRAT tmp= nullptr; PRAT one_pt_five= nullptr; PRAT a= nullptr; PRAT a2= nullptr; PRAT term= nullptr; PRAT sum= nullptr; PRAT err= nullptr; PRAT mpy= nullptr; PRAT ratprec = nullptr; PRAT ratRadix = nullptr; long oldprec; // Set up constants and initial conditions oldprec = precision; ratprec = longtorat( oldprec ); // Find the best 'A' for convergence to the required precision. a=longtorat( radix ); lograt(&a, precision); mulrat(&a, ratprec, precision); // Really is -ln(n)+1, but -ln(n) will be < 1 // if we scale n between 0.5 and 1.5 addrat(&a, rat_two, precision); DUPRAT(tmp,a); lograt(&tmp, precision); mulrat(&tmp, *pn, precision); addrat(&a, tmp, precision); addrat(&a, rat_one, precision); // Calculate the necessary bump in precision and up the precision. // The following code is equivalent to // precision += ln(exp(a)*pow(a,n+1.5))-ln(radix)); DUPRAT(tmp,*pn); one_pt_five=longtorat( 3L ); divrat( &one_pt_five, rat_two, precision); addrat( &tmp, one_pt_five, precision); DUPRAT(term,a); powratcomp( &term, tmp, radix, precision); DUPRAT( tmp, a ); exprat( &tmp, radix, precision); mulrat( &term, tmp, precision); lograt( &term, precision); ratRadix = longtorat(radix); DUPRAT(tmp,ratRadix); lograt( &tmp, precision); subrat( &term, tmp, precision); precision += rattolong( term, radix, precision); // Set up initial terms for series, refer to series in above comment block. DUPRAT(factorial,rat_one); // Start factorial out with one count = longtonum( 0L, BASEX ); DUPRAT(mpy,a); powratcomp(&mpy,*pn, radix, precision); // a2=a^2 DUPRAT(a2,a); mulrat(&a2, a, precision); // sum=(1/n)-(a/(n+1)) DUPRAT(sum,rat_one); divrat(&sum, *pn, precision); DUPRAT(tmp,*pn); addrat(&tmp, rat_one, precision); DUPRAT(term,a); divrat(&term, tmp, precision); subrat(&sum, term, precision); DUPRAT(err,ratRadix); NEGATE(ratprec); powratcomp(&err,ratprec, radix, precision); divrat(&err, ratRadix, precision); // Just get something not tiny in term DUPRAT(term, rat_two ); // Loop until precision is reached, or asked to halt. while ( !zerrat( term ) && rat_gt( term, err, precision) ) { addrat(pn, rat_two, precision); // WARNING: mixing numbers and rationals here. // for speed and efficiency. INC(count); mulnumx(&(factorial->pp),count); INC(count) mulnumx(&(factorial->pp),count); divrat(&factorial, a2, precision); DUPRAT(tmp,*pn); addrat( &tmp, rat_one, precision); destroyrat(term); createrat(term); DUPNUM(term->pp,count); DUPNUM(term->pq,num_one); addrat( &term, rat_one, precision); mulrat( &term, tmp, precision); DUPRAT(tmp,a); divrat( &tmp, term, precision); DUPRAT(term,rat_one); divrat( &term, *pn, precision); subrat( &term, tmp, precision); divrat (&term, factorial, precision); addrat( &sum, term, precision); ABSRAT(term); } // Multiply by factor. mulrat( &sum, mpy, precision); // And cleanup precision = oldprec; destroyrat(ratprec); destroyrat(err); destroyrat(term); destroyrat(a); destroyrat(a2); destroyrat(tmp); destroyrat(one_pt_five); destroynum(count); destroyrat(factorial); destroyrat(*pn); DUPRAT(*pn,sum); destroyrat(sum); }