123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- /* euclid.c
- *
- * Rational arithmetic routines
- *
- *
- *
- * SYNOPSIS:
- *
- *
- * typedef struct
- * {
- * double n; numerator
- * double d; denominator
- * }fract;
- *
- * radd( a, b, c ) c = b + a
- * rsub( a, b, c ) c = b - a
- * rmul( a, b, c ) c = b * a
- * rdiv( a, b, c ) c = b / a
- * euclid( &n, &d ) Reduce n/d to lowest terms,
- * return greatest common divisor.
- *
- * Arguments of the routines are pointers to the structures.
- * The double precision numbers are assumed, without checking,
- * to be integer valued. Overflow conditions are reported.
- */
-
- #include <math.h>
- #ifdef ANSIPROT
- extern double fabs ( double );
- extern double floor ( double );
- double euclid( double *, double * );
- #else
- double fabs(), floor(), euclid();
- #endif
- extern double MACHEP;
- #define BIG (1.0/MACHEP)
- typedef struct
- {
- double n; /* numerator */
- double d; /* denominator */
- }fract;
- /* Add fractions. */
- void radd( f1, f2, f3 )
- fract *f1, *f2, *f3;
- {
- double gcd, d1, d2, gcn, n1, n2;
- n1 = f1->n;
- d1 = f1->d;
- n2 = f2->n;
- d2 = f2->d;
- if( n1 == 0.0 )
- {
- f3->n = n2;
- f3->d = d2;
- return;
- }
- if( n2 == 0.0 )
- {
- f3->n = n1;
- f3->d = d1;
- return;
- }
- gcd = euclid( &d1, &d2 ); /* common divisors of denominators */
- gcn = euclid( &n1, &n2 ); /* common divisors of numerators */
- /* Note, factoring the numerators
- * makes overflow slightly less likely.
- */
- f3->n = ( n1 * d2 + n2 * d1) * gcn;
- f3->d = d1 * d2 * gcd;
- euclid( &f3->n, &f3->d );
- }
- /* Subtract fractions. */
- void rsub( f1, f2, f3 )
- fract *f1, *f2, *f3;
- {
- double gcd, d1, d2, gcn, n1, n2;
- n1 = f1->n;
- d1 = f1->d;
- n2 = f2->n;
- d2 = f2->d;
- if( n1 == 0.0 )
- {
- f3->n = n2;
- f3->d = d2;
- return;
- }
- if( n2 == 0.0 )
- {
- f3->n = -n1;
- f3->d = d1;
- return;
- }
- gcd = euclid( &d1, &d2 );
- gcn = euclid( &n1, &n2 );
- f3->n = (n2 * d1 - n1 * d2) * gcn;
- f3->d = d1 * d2 * gcd;
- euclid( &f3->n, &f3->d );
- }
- /* Multiply fractions. */
- void rmul( ff1, ff2, ff3 )
- fract *ff1, *ff2, *ff3;
- {
- double d1, d2, n1, n2;
- n1 = ff1->n;
- d1 = ff1->d;
- n2 = ff2->n;
- d2 = ff2->d;
- if( (n1 == 0.0) || (n2 == 0.0) )
- {
- ff3->n = 0.0;
- ff3->d = 1.0;
- return;
- }
- euclid( &n1, &d2 ); /* cross cancel common divisors */
- euclid( &n2, &d1 );
- ff3->n = n1 * n2;
- ff3->d = d1 * d2;
- /* Report overflow. */
- if( (fabs(ff3->n) >= BIG) || (fabs(ff3->d) >= BIG) )
- {
- mtherr( "rmul", OVERFLOW );
- return;
- }
- /* euclid( &ff3->n, &ff3->d );*/
- }
- /* Divide fractions. */
- void rdiv( ff1, ff2, ff3 )
- fract *ff1, *ff2, *ff3;
- {
- double d1, d2, n1, n2;
- n1 = ff1->d; /* Invert ff1, then multiply */
- d1 = ff1->n;
- if( d1 < 0.0 )
- { /* keep denominator positive */
- n1 = -n1;
- d1 = -d1;
- }
- n2 = ff2->n;
- d2 = ff2->d;
- if( (n1 == 0.0) || (n2 == 0.0) )
- {
- ff3->n = 0.0;
- ff3->d = 1.0;
- return;
- }
- euclid( &n1, &d2 ); /* cross cancel any common divisors */
- euclid( &n2, &d1 );
- ff3->n = n1 * n2;
- ff3->d = d1 * d2;
- /* Report overflow. */
- if( (fabs(ff3->n) >= BIG) || (fabs(ff3->d) >= BIG) )
- {
- mtherr( "rdiv", OVERFLOW );
- return;
- }
- /* euclid( &ff3->n, &ff3->d );*/
- }
- /* Euclidean algorithm
- * reduces fraction to lowest terms,
- * returns greatest common divisor.
- */
- double euclid( num, den )
- double *num, *den;
- {
- double n, d, q, r;
- n = *num; /* Numerator. */
- d = *den; /* Denominator. */
- /* Make numbers positive, locally. */
- if( n < 0.0 )
- n = -n;
- if( d < 0.0 )
- d = -d;
- /* Abort if numbers are too big for integer arithmetic. */
- if( (n >= BIG) || (d >= BIG) )
- {
- mtherr( "euclid", OVERFLOW );
- return(1.0);
- }
- /* Divide by zero, gcd = 1. */
- if(d == 0.0)
- return( 1.0 );
- /* Zero. Return 0/1, gcd = denominator. */
- if(n == 0.0)
- {
- /*
- if( *den < 0.0 )
- *den = -1.0;
- else
- *den = 1.0;
- */
- *den = 1.0;
- return( d );
- }
- while( d > 0.5 )
- {
- /* Find integer part of n divided by d. */
- q = floor( n/d );
- /* Find remainder after dividing n by d. */
- r = n - d * q;
- /* The next fraction is d/r. */
- n = d;
- d = r;
- }
- if( n < 0.0 )
- mtherr( "euclid", UNDERFLOW );
- *num /= n;
- *den /= n;
- return( n );
- }
|