]> git.donarmstrong.com Git - lilypond.git/blob - flower/rational.cc
release: 0.1.48
[lilypond.git] / flower / rational.cc
1 /*
2   rational.cc -- implement Rational
3   
4   source file of the Flower Library
5
6   (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8 #include <stdlib.h>
9 #include "rational.hh"
10 #include "string.hh"
11 #include "string-convert.hh"  
12 #include "libc-extension.hh"
13
14
15 Rational::operator bool () const
16 {
17   return sign_;
18 }
19
20 ostream &
21 operator << (ostream &o, Rational r)
22 {
23   o <<  r.str ();
24   return o;
25 }
26
27
28
29 Rational
30 Rational::truncated () const
31 {
32   return Rational(num_ - (num_ % den_), den_);
33 }
34
35 Rational::Rational ()
36 {
37   sign_ = 1;
38   num_ = den_ = 1;
39 }
40
41 Rational::Rational (int n, int d)
42 {
43   sign_ = ::sign (n) * ::sign (d);
44   num_ = abs (n);
45   den_ = abs (d);
46   normalise ();
47 }
48
49
50 static
51 int gcd (int a, int b)
52 {
53   int t;
54   while ((t = a % b))
55     {
56       a = b;
57       b = t;
58     }
59   return b;
60 }
61
62 static
63 int lcm (int a, int b)
64 {
65   return abs (a*b / gcd (a,b));
66 }
67
68 void
69 Rational::set_infinite (int s)
70 {
71   sign_ = ::sign (s) * 2; 
72 }
73
74 Rational
75 Rational::operator - () const
76 {
77   Rational r(*this);
78   r.negate ();
79   return r;
80 }
81
82 void
83 Rational::normalise ()
84 {
85   if (!sign_)
86     {
87       den_ = 1;
88       num_ = 0;
89       return ;
90     }
91   if (!den_)
92     sign_ = 2;
93   if (!num_)
94     sign_ = 0;
95
96   int g = gcd (num_ , den_);
97
98   num_ /= g;
99   den_ /= g;
100 }
101
102 int
103 Rational::sign () const
104 {
105   return ::sign (sign_);
106 }
107
108 bool
109 Rational::infty_b () const
110 {
111   return abs (sign_) > 1;
112 }
113
114 int
115 Rational::compare (Rational const &r, Rational const &s)
116 {
117   if (r.sign_ < s.sign_)
118     return -1;
119   else if (r.sign_ > s.sign_)
120     return 1;
121   else if (r.infty_b ())
122     return 0;
123
124   return  (r - s).sign ();
125 }
126
127 int
128 compare (Rational const &r, Rational const &s)
129 {
130   return Rational::compare (r, s );
131 }
132
133 Rational &
134 Rational::operator += (Rational r)
135 {
136   if (infty_b ())
137     ;
138   else if (r.infty_b ())
139     {
140       *this = r;
141     }
142   else 
143     {
144       int n = sign_ * num_ *r.den_ + r.sign_ * den_ * r.num_;
145       int d = den_ * r.den_;
146       sign_ =  ::sign (n) * ::sign(d);
147       num_ = abs (n);
148       den_ = abs (d);
149       normalise ();
150     }
151   return *this;
152 }
153     
154
155 /*
156   copied from libg++ 2.8.0
157  */ 
158 Rational::Rational(double x)
159 {
160   num_ = 0;
161   den_ = 1;
162   if (x != 0.0)
163     {
164       sign_ = ::sign (x);
165       x *= sign_;
166
167       const long shift = 15;         // a safe shift per step
168       const double width = 32768.0;  // = 2^shift
169       const int maxiter = 20;        // ought not be necessary, but just in case,
170       // max 300 bits of precision
171       int expt;
172       double mantissa = frexp(x, &expt);
173       long exponent = expt;
174       double intpart;
175       int k = 0;
176       while (mantissa != 0.0 && k++ < maxiter)
177         {
178           mantissa *= width;
179           mantissa = modf(mantissa, &intpart);
180           num_ <<= shift;
181           num_ += (long)intpart;
182           exponent -= shift;
183         }
184       if (exponent > 0)
185         num_ <<= exponent;
186       else if (exponent < 0)
187         den_ <<= -exponent;
188     } else {
189       sign_ =  0;
190     }
191   normalise();
192 }
193
194
195 void
196 Rational::invert ()
197 {
198   int r (num_);
199   num_  = den_;
200   den_ = r;
201 }
202
203 Rational &
204 Rational::operator *= (Rational r)
205 {
206   sign_ *= ::sign (r.sign_);
207   if (r.infty_b ())
208     {   
209       sign_ = sign () * 2;
210       goto exit_func;
211     }
212
213   num_ *= r.num_;
214   den_ *= r.den_;
215
216   normalise ();
217  exit_func:
218   return *this;
219 }
220   
221 Rational &
222 Rational::operator /= (Rational r)
223 {
224   r.invert ();
225   return (*this *= r);
226 }
227
228 void
229 Rational::negate ()
230 {
231   sign_ *= -1;
232 }
233
234 Rational&
235 Rational::operator -= (Rational r)
236 {
237   r.negate ();
238   return (*this += r);
239 }
240
241 /*
242   be paranoid about overiding libg++ stuff
243  */
244 Rational &
245 Rational::operator = (Rational const &r)
246 {
247   copy (r);
248   return *this;
249 }
250
251 Rational::Rational (Rational const &r)
252 {
253   copy (r);
254 }
255
256 Rational::operator String () const
257 {
258   return str ();
259 }
260
261 String
262 Rational::str () const
263 {
264   if (infty_b ())
265     {
266       String s (sign_ > 0 ? "" : "-" );
267       return String (s + "infinity");
268     }
269   String s (num ());
270   if (den () != 1 && num ())
271     s += "/" + String (den ());
272   return s;
273 }
274
275 int
276 sign (Rational r)
277 {
278   return r.sign ();
279 }