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