release commit
[lilypond.git] / flower / rational.cc
blob54ac55bdaf8cdc04b75a9a099e6e895afc7a237e
1 /*
2 rational.cc -- implement Rational
4 source file of the Flower Library
6 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include <math.h>
9 #include <stdlib.h>
10 #include "rational.hh"
11 #include "string.hh"
12 #include "string-convert.hh"
13 #include "libc-extension.hh"
15 Rational::operator double () const
17 return (double)sign_ * num_ / den_;
20 #ifdef STREAM_SUPPORT
21 ostream &
22 operator << (ostream &o, Rational r)
24 o << r.string ();
25 return o;
27 #endif
30 Rational
31 Rational::trunc_rat () const
33 return Rational (num_ - (num_ % den_), den_);
36 Rational::Rational ()
38 sign_ = 0;
39 num_ = den_ = 1;
42 Rational::Rational (int n, int d)
44 sign_ = ::sign (n) * ::sign (d);
45 num_ = abs (n);
46 den_ = abs (d);
47 normalise ();
50 Rational::Rational (int n)
52 sign_ = ::sign (n);
53 num_ = abs (n);
54 den_= 1;
57 static
58 int gcd (int a, int b)
60 int t;
61 while ((t = a % b))
63 a = b;
64 b = t;
66 return b;
69 #if 0
70 static
71 int lcm (int a, int b)
73 return abs (a*b / gcd (a,b));
75 #endif
77 void
78 Rational::set_infinite (int s)
80 sign_ = ::sign (s) * 2;
83 Rational
84 Rational::operator - () const
86 Rational r (*this);
87 r.negate ();
88 return r;
91 Rational
92 Rational::div_rat (Rational div) const
94 Rational r (*this);
95 r /= div;
96 return r.trunc_rat ();
99 Rational
100 Rational::mod_rat (Rational div) const
102 Rational r (*this);
103 r = (r / div - r.div_rat (div)) * div;
104 return r;
107 void
108 Rational::normalise ()
110 if (!sign_)
112 den_ = 1;
113 num_ = 0;
115 else if (!den_)
117 sign_ = 2;
118 num_ = 1;
120 else if (!num_)
122 sign_ = 0;
123 den_ = 1;
125 else
127 int g = gcd (num_ , den_);
129 num_ /= g;
130 den_ /= g;
134 Rational::sign () const
136 return ::sign (sign_);
140 Rational::compare (Rational const &r, Rational const &s)
142 if (r.sign_ < s.sign_)
143 return -1;
144 else if (r.sign_ > s.sign_)
145 return 1;
146 else if (r.is_infinity ())
147 return 0;
148 else if (r.sign_ == 0)
149 return 0;
150 else
152 return r.sign_ * ::sign (int (r.num_ * s.den_) - int (s.num_ * r.den_));
157 compare (Rational const &r, Rational const &s)
159 return Rational::compare (r, s );
162 Rational &
163 Rational::operator %= (Rational r)
165 *this = r.mod_rat (r);
166 return *this;
169 Rational &
170 Rational::operator += (Rational r)
172 if (is_infinity ())
174 else if (r.is_infinity ())
176 *this = r;
178 else
180 int n = sign_ * num_ *r.den_ + r.sign_ * den_ * r.num_;
181 int d = den_ * r.den_;
182 sign_ = ::sign (n) * ::sign (d);
183 num_ = abs (n);
184 den_ = abs (d);
185 normalise ();
187 return *this;
192 copied from libg++ 2.8.0
194 Rational::Rational (double x)
196 if (x != 0.0)
198 sign_ = ::sign (x);
199 x *= sign_;
201 int expt;
202 double mantissa = frexp (x, &expt);
204 const int FACT = 1 << 20;
207 Thanks to Afie for this too simple idea.
209 do not blindly substitute by libg++ code, since that uses
210 arbitrary-size integers. The rationals would overflow too
211 easily.
214 num_ = (unsigned int) (mantissa * FACT);
215 den_ = (unsigned int) FACT;
216 normalise ();
217 if (expt < 0)
218 den_ <<= -expt;
219 else
220 num_ <<= expt;
221 normalise ();
223 else
225 num_ = 0;
226 den_ = 1;
227 sign_ =0;
228 normalise ();
233 void
234 Rational::invert ()
236 int r (num_);
237 num_ = den_;
238 den_ = r;
241 Rational &
242 Rational::operator *= (Rational r)
244 sign_ *= ::sign (r.sign_);
245 if (r.is_infinity ())
247 sign_ = sign () * 2;
248 goto exit_func;
251 num_ *= r.num_;
252 den_ *= r.den_;
254 normalise ();
255 exit_func:
256 return *this;
259 Rational &
260 Rational::operator /= (Rational r)
262 r.invert ();
263 return (*this *= r);
266 void
267 Rational::negate ()
269 sign_ *= -1;
272 Rational&
273 Rational::operator -= (Rational r)
275 r.negate ();
276 return (*this += r);
279 String
280 Rational::to_string () const
282 if (is_infinity ())
284 String s (sign_ > 0 ? "" : "-" );
285 return String (s + "infinity");
288 String s = ::to_string (num ());
289 if (den () != 1 && num ())
290 s += "/" + ::to_string (den ());
291 return s;
295 Rational::to_int () const
297 return num () / den ();
301 sign (Rational r)
303 return r.sign ();
306 bool
307 Rational::is_infinity () const
309 return sign_ == 2 || sign_ == -2;