1 // rat.h: declaration of rational number class
2 //////////////////////////////////////////////////////////////////////////
3 //
4 // Copyright 1990-2012 John Cremona
5 //
6 // This file is part of the eclib package.
7 //
8 // eclib is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 2 of the License, or (at your
11 // option) any later version.
12 //
13 // eclib is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 // for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with eclib; if not, write to the Free Software Foundation,
20 // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 //
22 //////////////////////////////////////////////////////////////////////////
23
24 #if !defined(_ECLIB_RATIONAL_H)
25 #define _ECLIB_RATIONAL_H 1 //flags that this file has been included
26
27 #include <eclib/arith.h>
28
29 class rational {
30 friend class bigrational;
31 public:
32 // constructors
33 rational(long num_val=0, long den_val=1);
34 rational(const rational& q);
35 void operator=(const rational& q);
36
37 // rational manipulations
38 void cancel(); // cancel *this in situ
39 friend long num(const rational&); // the numerator
40 friend long den(const rational&); // the denominator
41 friend rational recip(const rational&); // reciprocal
42 friend long round(const rational&); // nearest integer
43
44 // Binary Operator Functions
45 friend rational operator+(const rational&, const rational&);
46 friend rational operator+(long, const rational&);
47 friend rational operator+(const rational&, long);
48 friend rational operator-(const rational&, const rational&);
49 friend rational operator-(long, const rational&);
50 friend rational operator-(const rational&, long);
51 friend rational operator*(const rational&, const rational&);
52 friend rational operator*(const rational&, long);
53 friend rational operator*(long, const rational&);
54 friend rational operator/(const rational&, const rational&);
55 friend rational operator/(const rational&, long);
56 friend rational operator/(long, const rational&);
57 friend int operator==(const rational&, const rational&);
58 friend int operator!=(const rational&, const rational&);
59 friend ostream& operator<< (ostream&s, const rational&);
60 friend istream& operator>> (istream& is, rational& r);
61 rational& operator+=(const rational&);
62 rational& operator+=(long);
63 rational& operator-=(const rational&);
64 rational& operator-=(long);
65 rational& operator*=(const rational&);
66 rational& operator*=(long);
67 rational& operator/=(const rational&);
68 rational& operator/=(long);
69 rational operator+() const;
70 rational operator-() const;
71 friend long floor(const rational& r);
72 friend long ceil(const rational& r);
73 operator double(); // conversion operator
74 #ifdef MPFP
75 operator bigfloat(); // conversion operator
76 #endif
77 // Implementation
78 private:
79 long n, d;
80 };
81
82
83 // Inline rational functions
84
cancel()85 inline void rational::cancel() // cancel *this in situ
86 {
87 long g = ::gcd(n,d);
88 if (g>1) {n/=g; d/=g;}
89 if (d<0) {n=-n; d=-d;}
90 }
91
rational(long num_val,long den_val)92 inline rational::rational(long num_val, long den_val)
93 {
94 n=num_val; d=den_val;
95 (*this).cancel();
96 }
97
rational(const rational & q)98 inline rational::rational(const rational& q) :n(q.n), d(q.d) {;}
99 inline void rational::operator=(const rational& q) {n=q.n; d=q.d;}
100
101 inline rational rational::operator+() const
102 {
103 return *this;
104 }
105
106 inline rational rational::operator-() const
107 {
108 return rational(-n, d);
109 }
110
111
112 // Definitions of compound-assignment operator member functions
113
114 inline rational& rational::operator+=(const rational& q2)
115 {
116 n = n*q2.d+d*q2.n;
117 d *= q2.d;
118 (*this).cancel();
119 return *this;
120 }
121
122 inline rational& rational::operator+=(long num_val2)
123 {
124 n += d*num_val2;
125 return *this;
126 }
127
128 inline rational& rational::operator-=(const rational& q2)
129 {
130 n = n*q2.d-d*q2.n;
131 d *= q2.d;
132 (*this).cancel();
133 return *this;
134 }
135
136 inline rational& rational::operator-=(long num_val2)
137 {
138 n -= d*num_val2;
139 return *this;
140 }
141
142 inline rational& rational::operator*=(const rational& q2)
143 {
144 n *= q2.n;
145 d *= q2.d;
146 (*this).cancel();
147 return *this;
148 }
149
150 inline rational& rational::operator*=(long num_val2)
151 {
152 n*=num_val2;
153 (*this).cancel();
154 return *this;
155 }
156
157 inline rational& rational::operator/=(long num_val2)
158 {
159 d*=num_val2;
160 (*this).cancel();
161 return *this;
162 }
163
164 inline rational::operator double() {return double(n)/double(d);}
165 #ifdef MPFP
bigfloat()166 inline rational::operator bigfloat() {return to_bigfloat(n)/to_bigfloat(d);}
167 #endif
168
169 // Definitions of non-member rational functions
170
num(const rational & q)171 inline long num(const rational& q)
172 {
173 return q.n;
174 }
175
den(const rational & q)176 inline long den(const rational& q)
177 {
178 return q.d;
179 }
180
recip(const rational & q)181 inline rational recip(const rational& q)
182 {
183 return rational(q.d, q.n);
184 }
185
round(const rational & q)186 inline long round(const rational& q)
187 {
188 return q.n / q.d; //provisional -- should fix rounding direction.
189 }
190
191 // Definitions of non-member binary operator functions
192
193 inline rational operator+(const rational& q1, const rational& q2)
194 {
195 return rational(q1.n*q2.d + q2.n*q1.d, q1.d * q2.d);
196 }
197
198 inline rational operator+(long num_val1, const rational& q2)
199 {
200 return rational(num_val1*q2.d + q2.n, q2.d);
201 }
202
203 inline rational operator+(const rational& q1, long num_val2)
204 {
205 return rational(q1.n + num_val2*q1.d, q1.d);
206 }
207
208 inline rational operator-(const rational& q1, const rational& q2)
209 {
210 return rational(q1.n*q2.d - q2.n*q1.d, q1.d * q2.d);
211 }
212
213 inline rational operator-(long num_val1, const rational& q2)
214 {
215 return rational(num_val1*q2.d - q2.n, q2.d);
216 }
217
218 inline rational operator-(const rational& q1, long num_val2)
219 {
220 return rational(q1.n - num_val2*q1.d, q1.d);
221 }
222
223 inline rational operator*(const rational& q1, long num_val2)
224 {
225 return rational(q1.n*num_val2, q1.d);
226 }
227
228 inline rational operator*(long num_val1, const rational& q2)
229 {
230 return rational(q2.n*num_val1, q2.d);
231 }
232
233 inline rational operator*(const rational& q1, const rational& q2)
234 {
235 return rational(q1.n*q2.n, q1.d*q2.d);
236 }
237
238 inline rational operator/(const rational& q1, long num_val2)
239 {
240 return rational(q1.n, q1.d*num_val2);
241 }
242
243 inline rational operator/(const rational& q1, const rational& q2)
244 {
245 return rational(q1.n*q2.d, q1.d*q2.n);
246 }
247
248 inline rational operator/(long num_val1, const rational& q2)
249 {
250 return rational(q2.d*num_val1, q2.n);
251 }
252
253 inline int operator==(const rational& q1, const rational& q2)
254 {
255 return q1.n*q2.d == q2.n*q1.d;
256 }
257
258 inline int operator!=(const rational& q1, const rational& q2)
259 {
260 return q1.n*q2.d != q2.n*q1.d;
261 }
262
263 inline ostream& operator<<(ostream& s, const rational& q)
264 {
265 if(q.d==0) s<<"oo";
266 else
267 {
268 s << q.n;
269 if (q.d!=1) {s << "/" << q.d;}
270 }
271 return s;
272 }
273
274 inline istream& operator>> (istream& is, rational& r)
275 {
276 char c;
277 long n,d=1;
278 is>>n;
279 if(!is.eof())
280 {
281 is.get(c);
282 if(c=='/')
283 {
284 is>>d;
285 }
286 else
287 {
288 is.putback(c);
289 }
290 }
291 r=rational(n,d);
292 return is;
293 }
294
295 // NB gcd(n,d)=1 and d>0:
296
floor(const rational & r)297 inline long floor(const rational& r)
298 {
299 return (r.n-(r.n%r.d))/r.d;
300 }
301
ceil(const rational & r)302 inline long ceil(const rational& r)
303 {
304 if(r.d==1) return r.n;
305 return 1 + (r.n-(r.n%r.d))/r.d;
306 }
307
308 #endif
309