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