windows-nt/Source/XPSP1/NT/shell/osshell/accesory/ratpak/itrans.c
2020-09-26 16:20:57 +08:00

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 );
}
}