Copyright (C) 1988 Free Software Foundation
written by Doug Lea (dl@rocky.oswego.edu)
This file is part of the GNU C++ Library. This library is free
software; you can redistribute it and/or modify it under the terms of
the GNU Library General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version. This library is distributed in the hope
that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
void Rational::error(const char* msg
) const
(*lib_error_handler
)("Rational", msg
);
static const Integer
_Int_One(1);
void Rational::normalize()
error("Zero denominator.");
Integer g
= gcd(num
, den
);
if (ucompare(g
, _Int_One
) != 0)
void add(const Rational
& x
, const Rational
& y
, Rational
& r
)
if (&r
!= &x
&& &r
!= &y
)
mul(x
.num
, y
.den
, r
.num
);
mul(x
.den
, y
.num
, r
.den
);
add(r
.num
, r
.den
, r
.num
);
mul(x
.den
, y
.den
, r
.den
);
mul(x
.num
, y
.den
, r
.num
);
mul(x
.den
, y
.den
, r
.den
);
void sub(const Rational
& x
, const Rational
& y
, Rational
& r
)
if (&r
!= &x
&& &r
!= &y
)
mul(x
.num
, y
.den
, r
.num
);
mul(x
.den
, y
.num
, r
.den
);
sub(r
.num
, r
.den
, r
.num
);
mul(x
.den
, y
.den
, r
.den
);
mul(x
.num
, y
.den
, r
.num
);
mul(x
.den
, y
.den
, r
.den
);
void mul(const Rational
& x
, const Rational
& y
, Rational
& r
)
mul(x
.num
, y
.num
, r
.num
);
mul(x
.den
, y
.den
, r
.den
);
void div(const Rational
& x
, const Rational
& y
, Rational
& r
)
if (&r
!= &x
&& &r
!= &y
)
mul(x
.num
, y
.den
, r
.num
);
mul(x
.den
, y
.num
, r
.den
);
mul(y
.num
, x
.den
, r
.den
);
error("Zero denominator.");
int compare(const Rational
& x
, const Rational
& y
)
if (d
== 0 && xsgn
!= 0) d
= compare(x
.num
* y
.den
, x
.den
* y
.num
);
Rational::Rational(double 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
double mantissa
= frexp(x
, &expt
);
while (mantissa
!= 0.0 && k
++ < maxiter
)
mantissa
= modf(mantissa
, &intpart
);
Integer
trunc(const Rational
& x
)
Rational
pow(const Rational
& x
, const Integer
& y
)
#if defined(__GNUG__) && !defined(NO_NRV)
Rational
operator - (const Rational
& x
) return r(x
)
Rational
abs(const Rational
& x
) return r(x
)
if (sign(r
.num
) < 0) r
.negate();
Rational
sqr(const Rational
& x
) return r
mul(x
.num
, x
.num
, r
.num
);
mul(x
.den
, x
.den
, r
.den
);
Integer
floor(const Rational
& x
) return q
divide(x
.num
, x
.den
, q
, r
);
if (sign(x
.num
) < 0 && sign(r
) != 0) --q
;
Integer
ceil(const Rational
& x
) return q
divide(x
.num
, x
.den
, q
, r
);
if (sign(x
.num
) >= 0 && sign(r
) != 0) ++q
;
Integer
round(const Rational
& x
) return q
divide(x
.num
, x
.den
, q
, r
);
if (ucompare(r
, x
.den
) >= 0)
// power: no need to normalize since num & den already relatively prime
Rational
pow(const Rational
& x
, long y
) return r
Rational
operator - (const Rational
& x
)
Rational
r(x
); r
.negate(); return r
;
Rational
abs(const Rational
& x
)
if (sign(r
.num
) < 0) r
.negate();
Rational
sqr(const Rational
& x
)
mul(x
.num
, x
.num
, r
.num
);
mul(x
.den
, x
.den
, r
.den
);
Integer
floor(const Rational
& x
)
divide(x
.num
, x
.den
, q
, r
);
if (sign(x
.num
) < 0 && sign(r
) != 0) --q
;
Integer
ceil(const Rational
& x
)
divide(x
.num
, x
.den
, q
, r
);
if (sign(x
.num
) >= 0 && sign(r
) != 0) ++q
;
Integer
round(const Rational
& x
)
divide(x
.num
, x
.den
, q
, r
);
if (ucompare(r
, x
.den
) >= 0)
Rational
pow(const Rational
& x
, long y
)
ostream
& operator << (ostream
& s
, const Rational
& y
)
if (y
.denominator() == 1L)
istream
& operator >> (istream
& s
, Rational
& y
)
s
.clear(ios::failbit
|s
.rdstate()); // Redundant if using GNU iostreams.
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");
Rational::fits_in_float() const
return Rational (FLT_MIN
) <= *this && *this <= Rational (FLT_MAX
);
Rational::fits_in_double() const
return Rational (DBL_MIN
) <= *this && *this <= Rational (DBL_MAX
);