]> git.donarmstrong.com Git - lilypond.git/blob - flower/rational.cc
release: 1.1.29
[lilypond.git] / flower / rational.cc
1 /*
2   rational.cc -- implement Rational
3   
4   source file of the Flower Library
5
6   (c)  1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.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 Rational
37 Rational::truncated () const
38 {
39   return Rational(num_ - (num_ % den_), den_);
40 }
41
42 Rational::Rational ()
43 {
44   sign_ = 0;
45   num_ = den_ = 1;
46 }
47
48 Rational::Rational (int n, int d)
49 {
50   sign_ = ::sign (n) * ::sign (d);
51   num_ = abs (n);
52   den_ = abs (d);
53   normalise ();
54 }
55
56 Rational::Rational (Rational const &r)
57 {
58   copy (r);
59 }
60
61 static
62 int gcd (int a, int b)
63 {
64   int t;
65   while ((t = a % b))
66     {
67       a = b;
68       b = t;
69     }
70   return b;
71 }
72
73 static
74 int lcm (int a, int b)
75 {
76   return abs (a*b / gcd (a,b));
77 }
78
79 void
80 Rational::set_infinite (int s)
81 {
82   sign_ = ::sign (s) * 2; 
83 }
84
85 Rational
86 Rational::operator - () const
87 {
88   Rational r(*this);
89   r.negate ();
90   return r;
91 }
92
93 void
94 Rational::normalise ()
95 {
96   if (!sign_)
97     {
98       den_ = 1;
99       num_ = 0;
100       return ;
101     }
102   if (!den_)
103     sign_ = 2;
104   if (!num_)
105     sign_ = 0;
106
107   int g = gcd (num_ , den_);
108
109   num_ /= g;
110   den_ /= g;
111 }
112
113 int
114 Rational::sign () const
115 {
116   return ::sign (sign_);
117 }
118
119 bool
120 Rational::infty_b () const
121 {
122   return abs (sign_) > 1;
123 }
124
125 int
126 Rational::compare (Rational const &r, Rational const &s)
127 {
128   if (r.sign_ < s.sign_)
129     return -1;
130   else if (r.sign_ > s.sign_)
131     return 1;
132   else if (r.infty_b ())
133     return 0;
134
135   return  (r - s).sign ();
136 }
137
138 int
139 compare (Rational const &r, Rational const &s)
140 {
141   return Rational::compare (r, s );
142 }
143
144 Rational &
145 Rational::operator += (Rational r)
146 {
147   if (infty_b ())
148     ;
149   else if (r.infty_b ())
150     {
151       *this = r;
152     }
153   else 
154     {
155       int n = sign_ * num_ *r.den_ + r.sign_ * den_ * r.num_;
156       int d = den_ * r.den_;
157       sign_ =  ::sign (n) * ::sign(d);
158       num_ = abs (n);
159       den_ = abs (d);
160       normalise ();
161     }
162   return *this;
163 }
164     
165
166 /*
167   copied from libg++ 2.8.0
168  */ 
169 Rational::Rational(double x)
170 {
171   if (x != 0.0)
172     {
173       sign_ = ::sign (x);
174       x *= sign_;
175
176       int expt;
177       double mantissa = frexp(x, &expt);
178
179       const int FACT = 1 << 20;
180
181       /*
182         Thanks to Afie for this too simple  idea.
183
184         do not blindly substitute by libg++ code, since that uses
185         arbitrary-size integers.  The rationals would overflow too
186         easily.
187       */
188
189       num_ = (unsigned int) (mantissa * FACT);
190       den_ = (unsigned int) FACT;
191       normalise ();      
192       if (expt < 0)
193         den_ <<= -expt;
194       else
195         num_ <<= expt;
196       normalise ();
197     }
198   else
199     {
200       num_ = 0;
201       den_ = 1;
202       sign_ =0;
203       normalise ();
204     }
205 }
206
207
208 void
209 Rational::invert ()
210 {
211   int r (num_);
212   num_  = den_;
213   den_ = r;
214 }
215
216 Rational &
217 Rational::operator *= (Rational r)
218 {
219   sign_ *= ::sign (r.sign_);
220   if (r.infty_b ())
221     {   
222       sign_ = sign () * 2;
223       goto exit_func;
224     }
225
226   num_ *= r.num_;
227   den_ *= r.den_;
228
229   normalise ();
230  exit_func:
231   return *this;
232 }
233   
234 Rational &
235 Rational::operator /= (Rational r)
236 {
237   r.invert ();
238   return (*this *= r);
239 }
240
241 void
242 Rational::negate ()
243 {
244   sign_ *= -1;
245 }
246
247 Rational&
248 Rational::operator -= (Rational r)
249 {
250   r.negate ();
251   return (*this += r);
252 }
253
254 /*
255   be paranoid about overiding libg++ stuff
256  */
257 Rational &
258 Rational::operator = (Rational const &r)
259 {
260   copy (r);
261   return *this;
262 }
263
264 String
265 Rational::str () const
266 {
267   if (infty_b ())
268     {
269       String s (sign_ > 0 ? "" : "-" );
270       return String (s + "infinity");
271     }
272   String s = to_str (num ());
273   if (den () != 1 && num ())
274     s += "/" + to_str (den ());
275   return s;
276 }
277
278 int
279 sign (Rational r)
280 {
281   return r.sign ();
282 }