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