394 lines
8.9 KiB
C
394 lines
8.9 KiB
C
//-----------------------------------------------------------------------------
|
|
// Package Title ratpak
|
|
// File itrans.c
|
|
// Author Timothy David Corrie Jr. (timc@microsoft.com)
|
|
// 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 );
|
|
}
|
|
}
|
|
|