00001
00004
00005
00006
00007
00008 #ifndef _cel_rational_h_
00009 #define _cel_rational_h_
00010
00011 #include "cel_types.h"
00012 #include "cel_endian.h"
00013 #include "cel_exception.h"
00014 #include "cel_datatraits.h"
00015 #include "cel_iostream.h"
00016
00017 namespace Celartem
00018 {
00019
00054 template<typename Int> struct Rational
00055 {
00059 Int num;
00060
00064 Int den;
00065
00069 Rational() : num(0), den(1) {}
00070
00076 Rational(const Int& n) : num(n), den(1) {}
00077
00086 Rational(const Int& n, const Int& d) : num(n), den(d) {normalize();}
00087
00094 Rational(const Rational& r) : num(r.num), den(r.den) {}
00095
00103 inline Rational& operator=(const Rational& r)
00104 {
00105 num = r.num;
00106 den = r.den;
00107 return *this;
00108 }
00109
00118 inline Rational& operator=(const Int& n)
00119 {
00120 num = n;
00121 den = 1;
00122 return *this;
00123 }
00124
00134 inline void assign(const Int& n, const Int& d)
00135 {
00136 num = n;
00137 den = d;
00138 normalize();
00139 }
00140
00151 void normalize()
00152 {
00153 if(den == zero())
00154 celThrow(errInvalidState);
00155
00156 if(num == zero())
00157 {
00158 den = 1;
00159 return;
00160 }
00161
00162 Int g = gcd(num, den);
00163 if(den < zero())
00164 g = zero() - g;
00165
00166 num /= g;
00167 den /= g;
00168 }
00169
00177 inline Rational& operator+=(const Rational& r)
00178 {
00179 Int g = gcd(den, r.den);
00180 den /= g;
00181 num = num * (r.den / g) + r.num * den;
00182 g = gcd(num, g);
00183 num /= g;
00184 den *= r.den / g;
00185 return *this;
00186 }
00187
00195 inline Rational& operator-=(const Rational& r)
00196 {
00197 Int g = gcd(den, r.den);
00198 den /= g;
00199 num = num * (r.den / g) - r.num * den;
00200 g = gcd(num, g);
00201 num /= g;
00202 den *= r.den / g;
00203 return *this;
00204 }
00205
00214 inline Rational& operator*=(const Rational& r)
00215 {
00216 Int gcd1 = gcd(num, r.den);
00217 Int gcd2 = gcd(r.num, den);
00218 num = (num / gcd1) * (r.num / gcd2);
00219 den = (den / gcd2) * (r.den / gcd1);
00220 return *this;
00221 }
00222
00233 inline Rational& operator/=(const Rational& r)
00234 {
00235 if(num == zero())
00236 return *this;
00237
00238 if(r.den == zero())
00239 celThrow(errDivByZero);
00240
00241 Int gcd1 = gcd(num, r.num);
00242 Int gcd2 = gcd(r.den, den);
00243 num = (num / gcd1) * (r.den / gcd2);
00244 den = (den / gcd2) * (r.num / gcd1);
00245 return *this;
00246 }
00247
00253 inline const Rational& operator++()
00254 {
00255 num += den;
00256 return *this;
00257 }
00258
00264 inline const Rational& operator--()
00265 {
00266 num -= den;
00267 return *this;
00268 }
00269
00277 Rational operator+(const Rational<Int>& r) const
00278 {
00279 Rational temp = *this;
00280 temp += r;
00281 return temp;
00282 }
00283
00291 Rational operator-(const Rational<Int>& r) const
00292 {
00293 Rational temp = *this;
00294 temp -= r;
00295 return temp;
00296 }
00297
00305 Rational operator*(const Rational<Int>& r) const
00306 {
00307 Rational temp = *this;
00308 temp *= r;
00309 return temp;
00310 }
00311
00319 Rational operator/(const Rational<Int>& r) const
00320 {
00321 Rational temp = *this;
00322 temp /= r;
00323 return temp;
00324 }
00325
00326 #if 0
00327
00333 Rational operator+() const
00334 {
00335 return *this;
00336 }
00337
00343 Rational operator-() const
00344 {
00345 return Rational(-r.num, r.den);
00346 }
00347 #endif
00348
00359 bool operator<(const Rational& r) const
00360 {
00361 if(num < zero() && r.num >= zero())
00362 return true;
00363 if(num >= zero() && r.num <= zero())
00364 return false;
00365
00366 Int gcd1 = gcd(num, r.num);
00367 Int gcd2 = gcd(r.den, den);
00368 return
00369 (num / gcd1) * (r.den / gcd2)
00370 < (den / gcd2) * (r.num / gcd1);
00371 }
00372
00383 inline bool operator<=(const Rational& r) const
00384 {
00385 return (*this == r) || (*this < r);
00386 }
00387
00398 inline bool operator==(const Rational& r) const
00399 {
00400 return (num == r.num && den == r.den);
00401 }
00402
00413 inline bool operator!=(const Rational& r) const
00414 {
00415 return (num != r.num || den != r.den);
00416 }
00417
00428 inline bool operator>(const Rational& r) const
00429 {
00430 return !(*this <= r);
00431 }
00432
00443 inline bool operator>=(const Rational& r) const
00444 {
00445 return !(*this < r);
00446 }
00447
00453 Rational reciprocal() const
00454 {
00455 return Rational(den, num);
00456 }
00457
00464 void serialize(
00465 Stream *inStream, size_t inLevel, Endian inEndian) const
00466 {
00467 write<Int>(inStream, num, inEndian);
00468 write<Int>(inStream, den, inEndian);
00469 }
00470
00477 void deserialize(
00478 Stream *inStream, size_t inLevel, Endian inEndian)
00479 {
00480 num = read<Int>(inStream, inEndian);
00481 den = read<Int>(inStream, inEndian);
00482 }
00483
00484 private:
00485 static inline const Int& zero()
00486 {
00487 static Int _zero(0);
00488 return _zero;
00489 }
00490
00491 static Int gcd(Int n, Int m)
00492 {
00493 if(n < zero()) n = zero() - n;
00494 if(m < zero()) m = zero() - m;
00495
00496 for(;;)
00497 {
00498 if(m == zero())
00499 return n;
00500 n %= m;
00501 if(n == zero())
00502 return m;
00503 m %= n;
00504 }
00505 }
00506
00507 static Int lcm(Int n, Int m)
00508 {
00509 if(n == zero() || n == zero())
00510 return zero();
00511 n /= gcd(n, m);
00512 n *= m;
00513 if(n < zero())
00514 return -n;
00515 return n;
00516 }
00517 };
00518
00523 template<typename Int> struct DataTraits< Rational<Int> >
00524 {
00525 static const CopyPolicy
00526 copyPolicy = byMemcpy;
00527 static const StoragePolicy
00528 storagePolicy = byClassMethods;
00529 };
00530
00538 typedef Rational<uint32_t> TIFF_RATIONAL;
00539
00547 typedef Rational<int32_t> TIFF_SRATIONAL;
00548
00549 template<> TIFF_RATIONAL swap<TIFF_RATIONAL>(const TIFF_RATIONAL& num);
00550 template<> TIFF_SRATIONAL swap<TIFF_SRATIONAL>(const TIFF_SRATIONAL& num);
00551 }
00552
00553 #endif // _cel_rational_h_