home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright (C) 1988 Free Software Foundation
- written by Doug Lea (dl@rocky.oswego.edu)
-
- This file is part of GNU CC.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU CC General Public
- License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- GNU CC, but only under the conditions described in the
- GNU CC General Public License. A copy of this license is
- supposed to have been given to you along with GNU CC so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies.
- */
-
- #include <Rational.h>
- #include <std.h>
- #include <math.h>
- #include "libconfig.h"
-
-
-
- void Rational::error(char* msg)
- {
- (*lib_error_handler)("Rational", msg);
- }
-
- static Integer _Int_One(1);
-
- void Rational::normalize()
- {
- int s = sign(den);
- if (s == 0)
- error("Zero denominator.");
- else if (s < 0)
- {
- den.negate();
- num.negate();
- }
-
- Integer g = gcd(num, den);
- if (ucompare(g, _Int_One) != 0)
- {
- num /= g;
- den /= g;
- }
- }
-
- RatTmp Rational::operator + (Rational& y)
- {
- return RatTmp(num * y.den + den * y.num, den * y.den);
- }
-
- RatTmp Rational::operator - (Rational& y)
- {
- return RatTmp(num * y.den - den * y.num, den * y.den);
- }
-
- RatTmp Rational::operator * (Rational& y)
- {
- return RatTmp(num * y.num, den * y.den);
- }
-
- RatTmp Rational::operator / (Rational& y)
- {
- return RatTmp(num * y.den, den * y.num);
- }
-
- RatTmp Rational::operator - ()
- {
- Integer d = den;
- return RatTmp(-num, d);
- }
-
- RatTmp RatTmp::operator - ()
- {
- num.negate();
- return *this;
- }
-
- RatTmp abs(Rational& x)
- {
- Integer d = x.den;
- return RatTmp(abs(x.num), d);
- }
-
- RatTmp abs(RatTmp& x)
- {
- x.num.abs();
- return x;
- }
-
- RatTmp sqr(Rational& x)
- {
- return RatTmp(x.num * x.num, x.den * x.den);
- }
-
- RatTmp sqr(RatTmp& x)
- {
- x.num *= x.num;
- x.den *= x.den;
- return x;
- }
-
- void Rational::operator +=(Rational& y)
- {
- num = num * y.den + den * y.num;
- den *= y.den;
- normalize();
- }
-
- void Rational::operator -=(Rational& y)
- {
- num = num * y.den - den * y.num;
- den *= y.den;
- normalize();
- }
-
- void Rational::operator *=(Rational& y)
- {
- num *= y.num;
- den *= y.den;
- normalize();
- }
-
- void Rational::operator /=(Rational& y)
- {
- if (&y == this)
- {
- Integer n = num * y.den;
- den *= y.num;
- num = n;
- }
- else
- {
- num *= y.den;
- den *= y.num;
- }
- normalize();
- }
-
- RatTmp RatTmp::operator + (Rational& y)
- {
- num = num * y.den + den * y.num;
- den *= y.den;
- normalize();
- return *this;
- }
-
- RatTmp RatTmp::operator - (Rational& y)
- {
- num = num * y.den - den * y.num;
- den *= y.den;
- normalize();
- return *this;
- }
-
- RatTmp RatTmp::operator * (Rational& y)
- {
- num *= y.num;
- den *= y.den;
- normalize();
- return *this;
- }
-
- RatTmp RatTmp::operator / (Rational& y)
- {
- if (&y == this)
- {
- Integer n = num * y.den;
- den *= y.num;
- num = n;
- }
- else
- {
- num *= y.den;
- den *= y.num;
- }
- normalize();
- return *this;
- }
-
- void Rational::invert()
- {
- Integer tmp = num;
- num = den;
- den = tmp;
- int s = sign(den);
- if (s == 0)
- error("Zero denominator.");
- else if (s < 0)
- {
- den.negate();
- num.negate();
- }
- }
-
- int compare(Rational& x, Rational& y)
- {
- int xsgn = sign(x.num);
- int ysgn = sign(y.num);
- int d = xsgn - ysgn;
- if (d == 0 && xsgn != 0) d = compare(x.num * y.den, x.den * y.num);
- return d;
- }
-
- Rational::Rational(double x)
- {
- num = 0;
- den = 1;
- if (x != 0.0)
- {
- int neg = x < 0;
- if (neg)
- x = -x;
-
- const long shift = 15; // a safe shift per step
- const double width = 32768.0; // = 2^shift
- const int maxiter = 20; // ought not be necessary, but just in case,
- // max 300 bits of precision
- int expt;
- double mantissa = frexp(x, &expt);
- long exponent = expt;
- double intpart;
- int k = 0;
- while (mantissa != 0.0 && k++ < maxiter)
- {
- mantissa *= width;
- mantissa = modf(mantissa, &intpart);
- num <<= shift;
- num += (long)intpart;
- exponent -= shift;
- }
- if (exponent > 0)
- num <<= exponent;
- else if (exponent < 0)
- den <<= -exponent;
- if (neg)
- num.negate();
- }
- normalize();
- }
-
- IntTmp floor(Rational& x)
- {
- Integer q, r;
- divide(x.num, x.den, q, r);
- if (sign(x.num) < 0 && sign(r) != 0) q--;
- return q;
- }
-
- IntTmp ceil(Rational& x)
- {
- Integer q, r;
- divide(x.num, x.den, q, r);
- if (sign(x.num) >= 0 && sign(r) != 0) q++;
- return q;
- }
-
- IntTmp round(Rational& x)
- {
- Integer q, r;
- divide(x.num, x.den, q, r);
- r <<= 1;
- if (ucompare(r, x.den) >= 0)
- {
- if (sign(x.num) >= 0)
- q++;
- else
- q--;
- }
- return q;
- }
-
- IntTmp trunc(Rational& x)
- {
- return x.num / x.den ;
- }
-
- IntTmp Rational::numerator()
- {
- Integer n = num;
- return n;
- }
-
- IntTmp Rational::denominator()
- {
- Integer d = den;
- return d;
- }
-
- RatTmp pow(Rational& x, Integer& y)
- {
- long yy = long(y);
- return pow(x, yy);
- }
-
- double Rational::operator double()
- {
- return ratio(num, den);
- }
-
-
- // power: no need to normalize since num & den already relatively prime
-
- RatTmp pow(Rational& x, long y)
- {
- Rational r;
- if (y >= 0)
- {
- r.num = pow(x.num, y);
- r.den = pow(x.den, y);
- }
- else
- {
- y = -y;
- r.den = pow(x.num, y);
- r.num = pow(x.den, y);
- if (sign(r.den) < 0)
- {
- r.num.negate();
- r.den.negate();
- }
- }
- return r;
- }
-
-
- ostream& operator << (ostream& s, Rational& y)
- {
- if (y.den == 1)
- s << Itoa(y.num);
- else
- {
- s << Itoa(y.num);
- s << "/";
- s << Itoa(y.den);
- }
- return s;
- }
-
- istream& operator >> (istream& s, Rational& y)
- {
- s >> y.num;
- if (s)
- {
- char ch = 0;
- s.get(ch);
- if (ch == '/')
- {
- s >> y.den;
- y.normalize();
- }
- else
- {
- s.unget(ch);
- y.den = 1;
- }
- }
- return s;
- }
-
- int Rational::OK()
- {
- int v = num.OK() && den.OK(); // have valid num and denom
- v &= sign(den) > 0; // denominator positive;
- v &= ucompare(gcd(num, den), _Int_One) == 0; // relatively prime
- if (!v) error("invariant failure");
- return v;
- }
-
-