|
|
//-----------------------------------------------------------------------------
// Package Title ratpak
// File rat.c
// Author Timothy David Corrie Jr. ([email protected])
// Copyright (C) 1995-96 Microsoft
// Date 01-16-95
//
//
// Description
//
// Contains mul, div, add, and other support functions for rationals.
//
//
//
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#if defined( DOS )
#include <dosstub.h>
#else
#include <windows.h>
#endif
#include <ratpak.h>
//-----------------------------------------------------------------------------
//
// FUNCTION: gcdrat
//
// ARGUMENTS: pointer to a rational.
//
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Divides p and q in rational by the G.C.D.
// of both. It was hoped this would speed up some
// calculations, and until the above trimming was done it
// did, but after trimming gcdratting, only slows things
// down.
//
//-----------------------------------------------------------------------------
void gcdrat( PRAT *pa )
{ PNUMBER pgcd=NULL; PRAT a=NULL;
a=*pa; pgcd = gcd( a->pp, a->pq );
if ( !zernum( pgcd ) ) { divnumx( &(a->pp), pgcd ); divnumx( &(a->pq), pgcd ); }
destroynum( pgcd ); *pa=a; }
//-----------------------------------------------------------------------------
//
// FUNCTION: fracrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes pointer.
//
// DESCRIPTION: Does the rational equivalent of frac(*pa);
//
//-----------------------------------------------------------------------------
void fracrat( PRAT *pa )
{ long trim; remnum( &((*pa)->pp), (*pa)->pq, BASEX ); //Get *pa back in the integer over integer form.
RENORMALIZE(*pa); }
//-----------------------------------------------------------------------------
//
// FUNCTION: mulrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa *= b.
// Assumes nRadix is the nRadix of both numbers.
//
//-----------------------------------------------------------------------------
void mulrat( PRAT *pa, PRAT b ) { // Only do the multiply if it isn't zero.
if ( !zernum( (*pa)->pp ) ) { mulnumx( &((*pa)->pp), b->pp ); mulnumx( &((*pa)->pq), b->pq ); trimit(pa); } else { // If it is zero, blast a one in the denominator.
DUPNUM( ((*pa)->pq), num_one ); }
#ifdef MULGCD
gcdrat( pa ); #endif
}
//-----------------------------------------------------------------------------
//
// FUNCTION: divrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa /= b.
// Assumes nRadix is the nRadix of both numbers.
//
//-----------------------------------------------------------------------------
void divrat( PRAT *pa, PRAT b )
{
if ( !zernum( (*pa)->pp ) ) { // Only do the divide if the top isn't zero.
mulnumx( &((*pa)->pp), b->pq ); mulnumx( &((*pa)->pq), b->pp );
if ( zernum( (*pa)->pq ) ) { // raise an exception if the bottom is 0.
throw( CALC_E_DIVIDEBYZERO ); } trimit(pa); } else { // Top is zero.
if ( zerrat( b ) ) { // If bottom is zero
// 0 / 0 is indefinite, raise an exception.
throw( CALC_E_INDEFINITE ); } else { // 0/x make a unique 0.
DUPNUM( ((*pa)->pq), num_one ); } }
#ifdef DIVGCD
gcdrat( pa ); #endif
}
//-----------------------------------------------------------------------------
//
// FUNCTION: subrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa += b.
// Assumes base is internal througought.
//
//-----------------------------------------------------------------------------
void subrat( PRAT *pa, PRAT b )
{ b->pp->sign *= -1; addrat( pa, b ); b->pp->sign *= -1; }
//-----------------------------------------------------------------------------
//
// FUNCTION: addrat
//
// ARGUMENTS: pointer to a rational a second rational.
//
// RETURN: None, changes first pointer.
//
// DESCRIPTION: Does the rational equivalent of *pa += b.
// Assumes base is internal througought.
//
//-----------------------------------------------------------------------------
void addrat( PRAT *pa, PRAT b )
{ PNUMBER bot=NULL;
if ( equnum( (*pa)->pq, b->pq ) ) { // Very special case, q's match.,
// make sure signs are involved in the calculation
// we have to do this since the optimization here is only
// working with the top half of the rationals.
(*pa)->pp->sign *= (*pa)->pq->sign; (*pa)->pq->sign = 1; b->pp->sign *= b->pq->sign; b->pq->sign = 1; addnum( &((*pa)->pp), b->pp, BASEX ); } else { // Usual case q's aren't the same.
DUPNUM( bot, (*pa)->pq ); mulnumx( &bot, b->pq ); mulnumx( &((*pa)->pp), b->pq ); mulnumx( &((*pa)->pq), b->pp ); addnum( &((*pa)->pp), (*pa)->pq, BASEX ); destroynum( (*pa)->pq ); (*pa)->pq = bot; trimit(pa); // Get rid of negative zeroes here.
(*pa)->pp->sign *= (*pa)->pq->sign; (*pa)->pq->sign = 1; }
#ifdef ADDGCD
gcdrat( pa ); #endif
}
//-----------------------------------------------------------------------------
//
// FUNCTION: rootrat
//
// PARAMETERS: y prat representation of number to take the root of
// n prat representation of the root to take.
//
// RETURN: bth root of a in rat form.
//
// EXPLANATION: This is now a stub function to powrat().
//
//-----------------------------------------------------------------------------
void rootrat( PRAT *py, PRAT n )
{ PRAT oneovern=NULL;
DUPRAT(oneovern,rat_one); divrat(&oneovern,n);
powrat( py, oneovern );
destroyrat(oneovern); }
//-----------------------------------------------------------------------------
//
// FUNCTION: zerrat
//
// ARGUMENTS: Rational number.
//
// RETURN: Boolean
//
// DESCRIPTION: Returns true if input is zero.
// False otherwise.
//
//-----------------------------------------------------------------------------
BOOL zerrat( PRAT a )
{ return( zernum(a->pp) ); }
|