X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=flower%2Frational.cc;h=5bcf7b39609396fe56908822e8190d209c12db31;hb=2c22efe5a46a37065b10c3f51c5d7db00d07d318;hp=11963238b576632ea3b4e0cbc85eb30aac322e92;hpb=13e79c0250d34b6bdfbafbc551ef64e8b59b2991;p=lilypond.git diff --git a/flower/rational.cc b/flower/rational.cc index 11963238b5..5bcf7b3960 100644 --- a/flower/rational.cc +++ b/flower/rational.cc @@ -1,18 +1,302 @@ /* - rational.cc -- implement Rational related functions + rational.cc -- implement Rational source file of the Flower Library - (c) 1997 Han-Wen Nienhuys + (c) 1997--2005 Han-Wen Nienhuys */ #include "rational.hh" -#include "string.hh" + +#include +#include + +#include "string-convert.hh" +#include "libc-extension.hh" + +Rational::operator double () const +{ + return ((double)sign_) * num_ / den_; +} + +Rational::operator bool () const +{ + return sign_ && num_; +} + +#ifdef STREAM_SUPPORT +ostream & +operator << (ostream &o, Rational r) +{ + o << r.string (); + return o; +} +#endif + +Rational +Rational::trunc_rat () const +{ + return Rational (num_ - (num_ % den_), den_); +} + +Rational::Rational () +{ + sign_ = 0; + num_ = den_ = 1; +} + +Rational::Rational (int n, int d) +{ + sign_ = ::sign (n) * ::sign (d); + num_ = abs (n); + den_ = abs (d); + normalise (); +} + +Rational::Rational (int n) +{ + sign_ = ::sign (n); + num_ = abs (n); + den_ = 1; +} + +static inline +int gcd (int a, int b) +{ + int t; + while ((t = a % b)) + { + a = b; + b = t; + } + return b; +} + +void +Rational::set_infinite (int s) +{ + sign_ = ::sign (s) * 2; +} + +Rational +Rational::operator - () const +{ + Rational r (*this); + r.negate (); + return r; +} + +Rational +Rational::div_rat (Rational div) const +{ + Rational r (*this); + r /= div; + return r.trunc_rat (); +} + +Rational +Rational::mod_rat (Rational div) const +{ + Rational r (*this); + r = (r / div - r.div_rat (div)) * div; + return r; +} void -print_rat (Rational const &m) +Rational::normalise () +{ + if (!sign_) + { + den_ = 1; + num_ = 0; + } + else if (!den_) + { + sign_ = 2; + num_ = 1; + } + else if (!num_) + { + sign_ = 0; + den_ = 1; + } + else + { + int g = gcd (num_, den_); + + num_ /= g; + den_ /= g; + } +} +int +Rational::sign () const +{ + return ::sign (sign_); +} + +int +Rational::compare (Rational const &r, Rational const &s) +{ + if (r.sign_ < s.sign_) + return -1; + else if (r.sign_ > s.sign_) + return 1; + else if (r.is_infinity ()) + return 0; + else if (r.sign_ == 0) + return 0; + return r.sign_ * ::sign (int (r.num_ * s.den_) - int (s.num_ * r.den_)); +} + +int +compare (Rational const &r, Rational const &s) { - cout << String (m) << flush; + return Rational::compare (r, s); } - +Rational & +Rational::operator %= (Rational r) +{ + *this = mod_rat (r); + return *this; +} + +Rational & +Rational::operator += (Rational r) +{ + if (is_infinity ()) + ; + else if (r.is_infinity ()) + *this = r; + else + { + int lcm = (den_ / gcd (r.den_, den_)) * r.den_; + int n = sign_ * num_ * (lcm / den_) + r.sign_ * r.num_ * (lcm / r.den_); + int d = lcm; + sign_ = ::sign (n) * ::sign (d); + num_ = abs (n); + den_ = abs (d); + normalise (); + } + return *this; +} + +/* + copied from libg++ 2.8.0 +*/ +Rational::Rational (double x) +{ + if (x != 0.0) + { + sign_ = ::sign (x); + x *= sign_; + + int expt; + double mantissa = frexp (x, &expt); + + const int FACT = 1 << 20; + + /* + Thanks to Afie for this too simple idea. + + do not blindly substitute by libg++ code, since that uses + arbitrary-size integers. The rationals would overflow too + easily. + */ + + num_ = (unsigned int) (mantissa * FACT); + den_ = (unsigned int) FACT; + normalise (); + if (expt < 0) + den_ <<= -expt; + else + num_ <<= expt; + normalise (); + } + else + { + num_ = 0; + den_ = 1; + sign_ = 0; + normalise (); + } +} + +void +Rational::invert () +{ + int r (num_); + num_ = den_; + den_ = r; +} + +Rational & +Rational::operator *= (Rational r) +{ + sign_ *= ::sign (r.sign_); + if (r.is_infinity ()) + { + sign_ = sign () * 2; + goto exit_func; + } + + num_ *= r.num_; + den_ *= r.den_; + + normalise (); + exit_func: + return *this; +} + +Rational & +Rational::operator /= (Rational r) +{ + r.invert (); + return (*this *= r); +} + +void +Rational::negate () +{ + sign_ *= -1; +} + +Rational & +Rational::operator -= (Rational r) +{ + r.negate (); + return (*this += r); +} + +String +Rational::to_string () const +{ + if (is_infinity ()) + { + String s (sign_ > 0 ? "" : "-"); + return String (s + "infinity"); + } + + String s = ::to_string (num ()); + if (den () != 1 && num ()) + s += "/" + ::to_string (den ()); + return s; +} + +int +Rational::to_int () const +{ + return num () / den (); +} + +int +sign (Rational r) +{ + return r.sign (); +} + +bool +Rational::is_infinity () const +{ + return sign_ == 2 || sign_ == -2; +}