|
|
//-----------------------------------------------------------------------------
// Package Title ratpak
// File itrans.c
// Author Timothy David Corrie Jr. ([email protected])
// Copyright (C) 1995-96 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains inverse sin, cos, tan functions for rationals
//
// Special Information
//
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( DOS )
#include <dosstub.h>
#else
#include <windows.h>
#endif
#include <ratpak.h>
void ascalerat( IN OUT PRAT *pa, IN ANGLE_TYPE angletype )
{ switch ( angletype ) { case ANGLE_RAD: break; case ANGLE_DEG: divrat( pa, two_pi ); mulrat( pa, rat_360 ); break; case ANGLE_GRAD: divrat( pa, two_pi ); mulrat( pa, rat_400 ); break; } }
//-----------------------------------------------------------------------------
//
// FUNCTION: asinrat, _asinrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// sine of
// RETURN: asin of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2 2
// \ ] (2j+1) X
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j (2j+2)*(2j+3)
// /__]
// j=0
//
// thisterm = X ; and stop when thisterm < precision used.
// 0 n
//
// If abs(x) > 0.85 then an alternate form is used
// pi/2-sgn(x)*asin(sqrt(1-x^2)
//
//
//-----------------------------------------------------------------------------
void _asinrat( PRAT *px )
{ CREATETAYLOR(); DUPRAT(pret,*px); DUPRAT(thisterm,*px); DUPNUM(n2,num_one);
do { NEXTTERM(xx,MULNUM(n2) MULNUM(n2) INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2)); } while ( !SMALL_ENOUGH_RAT( thisterm ) ); DESTROYTAYLOR(); }
void asinanglerat( IN OUT PRAT *pa, IN ANGLE_TYPE angletype )
{ asinrat( pa ); ascalerat( pa, angletype ); }
void asinrat( PRAT *px )
{ long sgn; PRAT pret=NULL; PRAT phack=NULL;
sgn = (*px)->pp->sign* (*px)->pq->sign;
(*px)->pp->sign = 1; (*px)->pq->sign = 1; // Nasty hack to avoid the really bad part of the asin curve near +/-1.
DUPRAT(phack,*px); subrat(&phack,rat_one); // Since *px might be epsilon near zero we must set it to zero.
if ( rat_le(phack,rat_smallest) && rat_ge(phack,rat_negsmallest) ) { destroyrat(phack); DUPRAT( *px, pi_over_two ); } else { destroyrat(phack); if ( rat_gt( *px, pt_eight_five ) ) { if ( rat_gt( *px, rat_one ) ) { subrat( px, rat_one ); if ( rat_gt( *px, rat_smallest ) ) { throw( CALC_E_DOMAIN ); } else { DUPRAT(*px,rat_one); } } DUPRAT(pret,*px); mulrat( px, pret ); (*px)->pp->sign *= -1; addrat( px, rat_one ); rootrat( px, rat_two ); _asinrat( px ); (*px)->pp->sign *= -1; addrat( px, pi_over_two ); destroyrat(pret); } else { _asinrat( px ); } } (*px)->pp->sign = sgn; (*px)->pq->sign = 1; }
//-----------------------------------------------------------------------------
//
// FUNCTION: acosrat, _acosrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// cosine of
// RETURN: acos of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2 2
// \ ] (2j+1) X
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j (2j+2)*(2j+3)
// /__]
// j=0
//
// thisterm = 1 ; and stop when thisterm < precision used.
// 0 n
//
// In this case pi/2-asin(x) is used. At least for now _acosrat isn't
// called.
//
//-----------------------------------------------------------------------------
void acosanglerat( IN OUT PRAT *pa, IN ANGLE_TYPE angletype )
{ acosrat( pa ); ascalerat( pa, angletype ); }
void _acosrat( PRAT *px )
{ CREATETAYLOR();
createrat(thisterm); thisterm->pp=longtonum( 1L, BASEX ); thisterm->pq=longtonum( 1L, BASEX );
DUPNUM(n2,num_one);
do { NEXTTERM(xx,MULNUM(n2) MULNUM(n2) INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2)); } while ( !SMALL_ENOUGH_RAT( thisterm ) );
DESTROYTAYLOR(); }
void acosrat( PRAT *px )
{ long sgn;
sgn = (*px)->pp->sign*(*px)->pq->sign;
(*px)->pp->sign = 1; (*px)->pq->sign = 1; if ( rat_equ( *px, rat_one ) ) { if ( sgn == -1 ) { DUPRAT(*px,pi); } else { DUPRAT( *px, rat_zero ); } } else { (*px)->pp->sign = sgn; asinrat( px ); (*px)->pp->sign *= -1; addrat(px,pi_over_two); } }
//-----------------------------------------------------------------------------
//
// FUNCTION: atanrat, _atanrat
//
// ARGUMENTS: x PRAT representation of number to take the inverse
// hyperbolic tangent of
//
// RETURN: atanh of x in PRAT form.
//
// EXPLANATION: This uses Taylor series
//
// n
// ___ 2
// \ ] (2j)*X (-1^j)
// \ thisterm ; where thisterm = thisterm * ---------
// / j j+1 j (2j+2)
// /__]
// j=0
//
// thisterm = X ; and stop when thisterm < precision used.
// 0 n
//
// If abs(x) > 0.85 then an alternate form is used
// asin(x/sqrt(q+x^2))
//
// And if abs(x) > 2.0 then this form is used.
//
// pi/2 - atan(1/x)
//
//-----------------------------------------------------------------------------
void atananglerat( IN OUT PRAT *pa, IN ANGLE_TYPE angletype )
{ atanrat( pa ); ascalerat( pa, angletype ); }
void _atanrat( PRAT *px )
{ CREATETAYLOR();
DUPRAT(pret,*px); DUPRAT(thisterm,*px);
DUPNUM(n2,num_one);
xx->pp->sign *= -1;
do { NEXTTERM(xx,MULNUM(n2) INC(n2) INC(n2) DIVNUM(n2)); } while ( !SMALL_ENOUGH_RAT( thisterm ) );
DESTROYTAYLOR(); }
void atan2rat( PRAT *py, PRAT x )
{ if ( rat_gt( x, rat_zero ) ) { if ( !zerrat( (*py) ) ) { divrat( py, x); atanrat( py ); } } else if ( rat_lt( x, rat_zero ) ) { if ( rat_gt( (*py), rat_zero ) ) { divrat( py, x); atanrat( py ); addrat( py, pi ); } else if ( rat_lt( (*py), rat_zero ) ) { divrat( py, x); atanrat( py ); subrat( py, pi ); } else // (*py) == 0
{ DUPRAT( *py, pi ); } } else // x == 0
{ if ( !zerrat( (*py) ) ) { int sign; sign=(*py)->pp->sign*(*py)->pq->sign; DUPRAT( *py, pi_over_two ); (*py)->pp->sign = sign; } else // (*py) == 0
{ DUPRAT( *py, rat_zero ); } } }
void atanrat( PRAT *px )
{ long sgn; PRAT tmpx=NULL;
sgn = (*px)->pp->sign * (*px)->pq->sign;
(*px)->pp->sign = 1; (*px)->pq->sign = 1; if ( rat_gt( (*px), pt_eight_five ) ) { if ( rat_gt( (*px), rat_two ) ) { (*px)->pp->sign = sgn; (*px)->pq->sign = 1; DUPRAT(tmpx,rat_one); divrat(&tmpx,(*px)); _atanrat(&tmpx); tmpx->pp->sign = sgn; tmpx->pq->sign = 1; DUPRAT(*px,pi_over_two); subrat(px,tmpx); destroyrat( tmpx ); } else { (*px)->pp->sign = sgn; DUPRAT(tmpx,*px); mulrat( &tmpx, *px ); addrat( &tmpx, rat_one ); rootrat( &tmpx, rat_two ); divrat( px, tmpx ); destroyrat( tmpx ); asinrat( px ); (*px)->pp->sign = sgn; (*px)->pq->sign = 1; } } else { (*px)->pp->sign = sgn; (*px)->pq->sign = 1; _atanrat( px ); } if ( rat_gt( *px, pi_over_two ) ) { subrat( px, pi ); } }
|