core/vnl/vnl_rational.h

Go to the documentation of this file.
00001 // This is core/vnl/vnl_rational.h
00002 #ifndef vnl_rational_h_
00003 #define vnl_rational_h_
00004 //:
00005 // \file
00006 // \brief High-precision rational numbers
00007 //
00008 // The  vnl_rational  class  provides  high-precision rational numbers and
00009 // arithmetic, using the built-in type long, for the numerator and denominator.
00010 // Implicit conversion to the system defined types short, int, long, float, and
00011 // double is supported by  overloaded  operator member functions.  Although the
00012 // rational class makes judicious use of inline  functions and  deals only with
00013 // integral values, the user  is warned that  the rational  integer  arithmetic
00014 // class is still considerably slower than the built-in  integer data types. If
00015 // the range  of values  anticipated will  fit into a  built-in  type, use that
00016 // instead.
00017 //
00018 // In  addition  to  the  original  COOL Rational class, vnl_rational is able to
00019 // represent plus and minus infinity.  An  other  interesting  addition  is  the
00020 // possibility  to construct a rational from a double.  This allows for lossless
00021 // conversion from e.g. double 1.0/3.0 to the rational number 1/3, hence no more
00022 // rounding errors.  This is implemented with continued fraction approximations.
00023 //
00024 // \author
00025 // Copyright (C) 1991 Texas Instruments Incorporated.
00026 //
00027 // Permission is granted to any individual or institution to use, copy, modify,
00028 // and distribute this software, provided that this complete copyright and
00029 // permission notice is maintained, intact, in all copies and supporting
00030 // documentation.
00031 //
00032 // Texas Instruments Incorporated provides this software "as is" without
00033 // express or implied warranty.
00034 //
00035 // \verbatim
00036 // Modifications
00037 //  Peter Vanroose, 13 July 2001: Added continued fraction cnstrctr from double
00038 //  Peter Vanroose, 10 July 2001: corrected operator%=()
00039 //  Peter Vanroose, 10 July 2001: corrected ceil() and floor() for negative args
00040 //  Peter Vanroose, 10 July 2001: extended operability range of += by using gcd
00041 //  Peter Vanroose, 10 July 2001: added abs().
00042 //  Peter Vanroose, 10 July 2001: removed state data member and added Inf repres
00043 //  Peter Vanroose,  9 July 2001: ported to vnl from COOL
00044 // \endverbatim
00045 
00046 #include <vcl_iostream.h>
00047 #include <vcl_cassert.h>
00048 
00049 //: High-precision rational numbers
00050 //
00051 // The  vnl_rational  class  provides  high-precision rational numbers and
00052 // arithmetic, using the built-in type long, for the numerator and denominator.
00053 // Implicit conversion to the system defined types short, int, long, float, and
00054 // double is supported by  overloaded  operator member functions.  Although the
00055 // rational class makes judicious use of inline  functions and  deals only with
00056 // integral values, the user  is warned that  the rational  integer  arithmetic
00057 // class is still considerably slower than the built-in  integer data types. If
00058 // the range  of values  anticipated will  fit into a  built-in  type, use that
00059 // instead.
00060 //
00061 // In  addition  to  the  original  COOL Rational class, vnl_rational is able to
00062 // represent plus and minus infinity.  An  other  interesting  addition  is  the
00063 // possibility  to construct a rational from a double.  This allows for lossless
00064 // conversion from e.g. double 1.0/3.0 to the rational number 1/3, hence no more
00065 // rounding errors.  This is implemented with continued fraction approximations.
00066 //
00067 class vnl_rational
00068 {
00069   long num_; //!< Numerator portion
00070   long den_; //!< Denominator portion
00071 
00072  public:
00073   //: Creates a rational with given numerator and denominator.
00074   //  Default constructor gives 0.
00075   //  Also serves as automatic cast from long to vnl_rational.
00076   //  The only input which is not allowed is (0,0);
00077   //  the denominator is allowed to be 0, to represent +Inf or -Inf.
00078   inline vnl_rational (long num = 0L, long den = 1L)
00079     : num_(num), den_(den) { assert(num!=0||den!=0); normalize(); }
00080   //: Creates a rational with given numerator and denominator.
00081   //  Note these are not automatic type conversions because of a bug
00082   //  in the Borland compiler.  Since these just convert their
00083   //  arguments to long anyway, there is no harm in letting
00084   //  the long overload be used for automatic conversions.
00085   explicit inline vnl_rational (int num, int den = 1)
00086     : num_(num), den_(den) { assert(num!=0||den!=0); normalize(); }
00087   explicit inline vnl_rational (unsigned int num, unsigned int den = 1)
00088     : num_((long)num), den_((long)den) { assert(num!=0||den!=0); normalize(); }
00089   //: Creates a rational from a double.
00090   //  This is done by computing the continued fraction approximation for d.
00091   //  Note that this is explicitly *not* an automatic type conversion.
00092   explicit vnl_rational (double d);
00093   //  Copy constructor
00094   inline vnl_rational (vnl_rational const& from)
00095     : num_(from.numerator()), den_(from.denominator()) {}
00096   //  Destructor
00097   inline ~vnl_rational() {}
00098   //  Assignment: overwrite an existing vnl_rational
00099   inline void set(long num, long den) { assert(num!=0||den!=0); num_=num; den_=den; normalize(); }
00100 
00101   //: Return the numerator of the (simplified) rational number representation
00102   inline long numerator () const { return num_; }
00103   //: Return the denominator of the (simplified) rational number representation
00104   inline long denominator () const { return den_; }
00105 
00106   //: Copies the contents and state of rhs rational over to the lhs
00107   inline vnl_rational& operator= (vnl_rational const& rhs) {
00108     num_ = rhs.numerator(); den_ = rhs.denominator(); return *this; }
00109 
00110   //: Returns true if the two rationals have the same representation
00111   inline bool operator== (vnl_rational const& rhs) const {
00112     return num_ == rhs.numerator() && den_ == rhs.denominator(); }
00113   inline bool operator!= (vnl_rational const& rhs) const { return !operator==(rhs); }
00114   inline bool operator== (long rhs) const { return num_ == rhs && den_ == 1; }
00115   inline bool operator!= (long rhs) const { return !operator==(rhs); }
00116   inline bool operator== (int rhs) const { return num_ == rhs && den_ == 1; }
00117   inline bool operator!= (int rhs) const { return !operator==(rhs); }
00118 
00119   //: Unary minus - returns the negation of the current rational.
00120   inline vnl_rational operator-() const { return vnl_rational(-num_, den_); }
00121   //: Unary plus - returns the current rational.
00122   inline vnl_rational operator+() const { return *this; }
00123   //: Unary not - returns true if rational is equal to zero.
00124   inline bool operator!() const { return num_ == 0L; }
00125   //: Returns the absolute value of the current rational.
00126   inline vnl_rational abs() const { return vnl_rational(num_<0?-num_:num_, den_); }
00127   //: Replaces rational with 1/rational and returns it.
00128   //  Inverting 0 gives +Inf, inverting +-Inf gives 0.
00129   vnl_rational& invert () {
00130     long t = num_; num_ = den_; den_ = t; normalize(); return *this; }
00131 
00132   //: Plus/assign: replace lhs by lhs + rhs
00133   //  Note that +Inf + -Inf and -Inf + +Inf are undefined.
00134   inline vnl_rational& operator+= (vnl_rational const& r) {
00135     if (den_ == r.denominator()) num_ += r.numerator();
00136     else { long c = vnl_rational::gcd(den_,r.denominator()); if (c==0) c=1;
00137            num_ = num_*(r.denominator()/c) + (den_/c)*r.numerator();
00138            den_ *= r.denominator()/c; }
00139     assert(num_!=0 || den_ != 0); // +Inf + -Inf is undefined
00140     normalize (); return *this;
00141   }
00142   inline vnl_rational& operator+= (long r) { num_ += den_*r; return *this; }
00143   //: Minus/assign: replace lhs by lhs - rhs
00144   //  Note that +Inf - +Inf and -Inf - -Inf are undefined.
00145   inline vnl_rational& operator-= (vnl_rational const& r) {
00146     if (den_ == r.denominator()) num_ -= r.num_;
00147     else { long c = vnl_rational::gcd(den_,r.denominator()); if (c==0) c=1;
00148            num_ = num_*(r.denominator()/c) - (den_/c)*r.numerator();
00149            den_ *= r.denominator()/c; }
00150     assert(num_!=0 || den_ != 0); // +Inf - +Inf is undefined
00151     normalize (); return *this;
00152   }
00153   inline vnl_rational& operator-= (long r) { num_ -= den_*r; return *this; }
00154   //: Multiply/assign: replace lhs by lhs * rhs
00155   //  Note that 0 * Inf and Inf * 0 are undefined.
00156   inline vnl_rational& operator*= (vnl_rational const& r) {
00157     num_ *= r.numerator(); den_ *= r.denominator();
00158     assert(num_!=0 || den_ != 0); // 0 * Inf is undefined
00159     normalize (); return *this;
00160   }
00161   inline vnl_rational& operator*= (long r) {num_*=r;normalize();return *this;}
00162   //: Divide/assign: replace lhs by lhs / rhs
00163   //  Note that 0 / 0 and Inf / Inf are undefined.
00164   inline vnl_rational& operator/= (vnl_rational const& r) {
00165     num_ *= r.denominator(); den_ *= r.numerator();
00166     assert(num_!=0 || den_ != 0); // 0/0, Inf/Inf undefined
00167     normalize (); return *this;
00168   }
00169   inline vnl_rational& operator/= (long r) {
00170     den_ *= r; assert(num_!=0 || den_ != 0); // 0/0 undefined
00171     normalize (); return *this;
00172   }
00173   //: Modulus/assign: replace lhs by lhs % rhs
00174   //  Note that r % Inf is r, and that r % 0 and Inf % r are undefined.
00175   inline vnl_rational& operator%= (vnl_rational const& r) {
00176     assert(r.numerator() != 0);
00177     if (den_ == r.denominator()) num_ %= r.numerator();
00178     else { long c = vnl_rational::gcd(den_,r.denominator()); if (c==0) c=1;
00179            num_ *= r.denominator()/c;
00180            num_ %= (den_/c)*r.numerator();
00181            den_ *= r.denominator()/c; }
00182     normalize (); return *this;
00183   }
00184   inline vnl_rational& operator%=(long r){assert(r);num_%=den_*r;normalize();return *this;}
00185 
00186   //: Pre-increment (++r).  No-op when +-Inf.
00187   inline vnl_rational& operator++ () { num_ += den_; return *this; }
00188   //: Pre-decrement (--r).  No-op when +-Inf.
00189   inline vnl_rational& operator-- () { num_ -= den_; return *this; }
00190   //: Post-increment (r++).  No-op when +-Inf.
00191   inline vnl_rational operator++(int){vnl_rational b=*this;num_+=den_;return b;}
00192   //: Post-decrement (r--).  No-op when +-Inf.
00193   inline vnl_rational operator--(int){vnl_rational b=*this;num_-=den_;return b;}
00194 
00195   inline bool operator< (vnl_rational const& rhs) const {
00196     if (den_ == rhs.denominator())   // If same denominator
00197       return num_ < rhs.numerator(); // includes the case -Inf < +Inf
00198     // note that denominator is always >= 0:
00199     else
00200       return num_ * rhs.denominator() < den_ * rhs.numerator();
00201   }
00202   inline bool operator> (vnl_rational const& r) const { return r < *this; }
00203   inline bool operator<= (vnl_rational const& r) const { return !operator>(r); }
00204   inline bool operator>= (vnl_rational const& r) const { return !operator<(r); }
00205   inline bool operator< (long r) const { return num_ < den_ * r; }
00206   inline bool operator> (long r) const { return num_ > den_ * r; }
00207   inline bool operator<= (long r) const { return !operator>(r); }
00208   inline bool operator>= (long r) const { return !operator<(r); }
00209   inline bool operator< (int r) const { return num_ < den_ * r; }
00210   inline bool operator> (int r) const { return num_ > den_ * r; }
00211   inline bool operator<= (int r) const { return !operator>(r); }
00212   inline bool operator>= (int r) const { return !operator<(r); }
00213   inline bool operator< (double r) const { return num_ < den_ * r; }
00214   inline bool operator> (double r) const { return num_ > den_ * r; }
00215   inline bool operator<= (double r) const { return !operator>(r); }
00216   inline bool operator>= (double r) const { return !operator<(r); }
00217 
00218   //: Converts rational value to integer by truncating towards zero.
00219   inline long truncate () const { assert(den_ != 0);  return num_/den_; }
00220   //: Converts rational value to integer by truncating towards negative infinity.
00221   inline long floor () const { long t = truncate();
00222     return num_<0L && (num_%den_) != 0 ? t-1 : t; }
00223   //: Converts rational value to integer by truncating towards positive infinity.
00224   inline long ceil () const { long t = truncate();
00225     return num_>0L && (num_%den_) != 0 ? t+1 : t; }
00226   //: Rounds rational to nearest integer.
00227   inline long round () const { long t = truncate();
00228     if (num_ < 0) return ((-num_)%den_) >= 0.5*den_ ? t-1 : t;
00229     else          return   (num_ %den_) >= 0.5*den_ ? t+1 : t;
00230   }
00231 
00232   // Implicit conversions
00233   inline operator short () {
00234     long t = truncate (); short r = (short)t;
00235     assert(r == t); // abort on underflow or overflow
00236     return r;
00237   }
00238   inline operator int () {
00239     long t = truncate (); int r = (int)t;
00240     assert(r == t); // abort on underflow or overflow
00241     return r;
00242   }
00243   inline operator long () const { return truncate(); }
00244   inline operator long () { return truncate(); }
00245   inline operator float () const { return ((float)num_)/((float)den_); }
00246   inline operator float () { return ((float)num_)/((float)den_); }
00247   inline operator double () const { return ((double)num_)/((double)den_); }
00248   inline operator double () { return ((double)num_)/((double)den_); }
00249 
00250   //: Calculate greatest common divisor of two integers.
00251   //  Used to simplify rational number.
00252   static inline long gcd (long l1, long l2) {
00253     while (l2!=0) { long t = l2; l2 = l1 % l2; l1 = t; }
00254     return l1<0 ? (-l1) : l1;
00255   }
00256 
00257  private:
00258   //: Private function to normalize numerator/denominator of rational number.
00259   //  If num_ and den_ are both nonzero, their gcd is made 1 and den_ made positive.
00260   //  Otherwise, the nonzero den_ is set to 1 or the nonzero num_ to +1 or -1.
00261   inline void normalize () {
00262     if (num_ == 0) { den_ = 1; return; } // zero
00263     if (den_ == 0) { num_ = (num_>0) ? 1 : -1; return; } // +-Inf
00264     if (num_ != 1 && num_ != -1 && den_ != 1) {
00265       long common = vnl_rational::gcd (num_, den_);
00266       if (common != 1) { num_ /= common; den_ /= common; }
00267     }
00268     // if negative, put sign in numerator:
00269     if (den_ < 0) { num_ *= -1; den_ *= -1; }
00270   }
00271 };
00272 
00273 //: formatted output
00274 // \relates vnl_rational
00275 inline vcl_ostream& operator<< (vcl_ostream& s, vnl_rational const& r)
00276 {
00277   return s << r.numerator() << '/' << r.denominator();
00278 }
00279 
00280 //: simple input
00281 // \relates vnl_rational
00282 inline vcl_istream& operator>> (vcl_istream& s, vnl_rational& r)
00283 {
00284   long n, d; s >> n >> d;
00285   r.set(n,d); return s;
00286 }
00287 
00288 //: Returns the sum of two rational numbers.
00289 // \relates vnl_rational
00290 inline vnl_rational operator+ (vnl_rational const& r1, vnl_rational const& r2)
00291 {
00292   vnl_rational result(r1); return result += r2;
00293 }
00294 
00295 inline vnl_rational operator+ (vnl_rational const& r1, long r2)
00296 {
00297   vnl_rational result(r1); return result += r2;
00298 }
00299 
00300 inline vnl_rational operator+ (vnl_rational const& r1, int r2)
00301 {
00302   vnl_rational result(r1); return result += (long)r2;
00303 }
00304 
00305 inline vnl_rational operator+ (long r2, vnl_rational const& r1)
00306 {
00307   vnl_rational result(r1); return result += r2;
00308 }
00309 
00310 inline vnl_rational operator+ (int r2, vnl_rational const& r1)
00311 {
00312   vnl_rational result(r1); return result += (long)r2;
00313 }
00314 
00315 //: Returns the difference of two rational numbers.
00316 // \relates vnl_rational
00317 inline vnl_rational operator- (vnl_rational const& r1, vnl_rational const& r2)
00318 {
00319   vnl_rational result(r1); return result -= r2;
00320 }
00321 
00322 inline vnl_rational operator- (vnl_rational const& r1, long r2)
00323 {
00324   vnl_rational result(r1); return result -= r2;
00325 }
00326 
00327 inline vnl_rational operator- (vnl_rational const& r1, int r2)
00328 {
00329   vnl_rational result(r1); return result -= (long)r2;
00330 }
00331 
00332 inline vnl_rational operator- (long r2, vnl_rational const& r1)
00333 {
00334   vnl_rational result(-r1); return result += r2;
00335 }
00336 
00337 inline vnl_rational operator- (int r2, vnl_rational const& r1)
00338 {
00339   vnl_rational result(-r1); return result += (long)r2;
00340 }
00341 
00342 //: Returns the product of two rational numbers.
00343 // \relates vnl_rational
00344 inline vnl_rational operator* (vnl_rational const& r1, vnl_rational const& r2)
00345 {
00346   vnl_rational result(r1); return result *= r2;
00347 }
00348 
00349 inline vnl_rational operator* (vnl_rational const& r1, long r2)
00350 {
00351   vnl_rational result(r1); return result *= r2;
00352 }
00353 
00354 inline vnl_rational operator* (vnl_rational const& r1, int r2)
00355 {
00356   vnl_rational result(r1); return result *= (long)r2;
00357 }
00358 
00359 inline vnl_rational operator* (long r2, vnl_rational const& r1)
00360 {
00361   vnl_rational result(r1); return result *= r2;
00362 }
00363 
00364 inline vnl_rational operator* (int r2, vnl_rational const& r1)
00365 {
00366   vnl_rational result(r1); return result *= (long)r2;
00367 }
00368 
00369 //: Returns the quotient of two rational numbers.
00370 // \relates vnl_rational
00371 inline vnl_rational operator/ (vnl_rational const& r1, vnl_rational const& r2)
00372 {
00373   vnl_rational result(r1); return result /= r2;
00374 }
00375 
00376 inline vnl_rational operator/ (vnl_rational const& r1, long r2)
00377 {
00378   vnl_rational result(r1); return result /= r2;
00379 }
00380 
00381 inline vnl_rational operator/ (vnl_rational const& r1, int r2)
00382 {
00383   vnl_rational result(r1); return result /= (long)r2;
00384 }
00385 
00386 inline vnl_rational operator/ (long r1, vnl_rational const& r2)
00387 {
00388   vnl_rational result(r1); return result /= r2;
00389 }
00390 
00391 inline vnl_rational operator/ (int r1, vnl_rational const& r2)
00392 {
00393   vnl_rational result((long)r1); return result /= r2;
00394 }
00395 
00396 //: Returns the remainder of r1 divided by r2.
00397 // \relates vnl_rational
00398 inline vnl_rational operator% (vnl_rational const& r1, vnl_rational const& r2)
00399 {
00400   vnl_rational result(r1); return result %= r2;
00401 }
00402 
00403 inline vnl_rational operator% (vnl_rational const& r1, long r2)
00404 {
00405   vnl_rational result(r1); return result %= r2;
00406 }
00407 
00408 inline vnl_rational operator% (vnl_rational const& r1, int r2)
00409 {
00410   vnl_rational result(r1); return result %= (long)r2;
00411 }
00412 
00413 inline vnl_rational operator% (long r1, vnl_rational const& r2)
00414 {
00415   vnl_rational result(r1); return result %= r2;
00416 }
00417 
00418 inline vnl_rational operator% (int r1, vnl_rational const& r2)
00419 {
00420   vnl_rational result((long)r1); return result %= r2;
00421 }
00422 
00423 inline bool operator== (int  r1, vnl_rational const& r2) { return r2==r1; }
00424 inline bool operator== (long r1, vnl_rational const& r2) { return r2==r1; }
00425 inline bool operator!= (int  r1, vnl_rational const& r2) { return r2!=r1; }
00426 inline bool operator!= (long r1, vnl_rational const& r2) { return r2!=r1; }
00427 inline bool operator<  (int  r1, vnl_rational const& r2) { return r2> r1; }
00428 inline bool operator<  (long r1, vnl_rational const& r2) { return r2> r1; }
00429 inline bool operator>  (int  r1, vnl_rational const& r2) { return r2< r1; }
00430 inline bool operator>  (long r1, vnl_rational const& r2) { return r2< r1; }
00431 inline bool operator<= (int  r1, vnl_rational const& r2) { return r2>=r1; }
00432 inline bool operator<= (long r1, vnl_rational const& r2) { return r2>=r1; }
00433 inline bool operator>= (int  r1, vnl_rational const& r2) { return r2<=r1; }
00434 inline bool operator>= (long r1, vnl_rational const& r2) { return r2<=r1; }
00435 
00436 inline long truncate (vnl_rational const& r) { return r.truncate(); }
00437 inline long floor (vnl_rational const& r) { return r.floor(); }
00438 inline long ceil (vnl_rational const& r) { return r.ceil(); }
00439 inline long round (vnl_rational const& r) { return r.round(); }
00440 
00441 inline vnl_rational vnl_math_abs(vnl_rational const& x) { return x<0L ? -x : x; }
00442 inline vnl_rational vnl_math_squared_magnitude(vnl_rational const& x) { return x*x; }
00443 inline vnl_rational vnl_math_sqr(vnl_rational const& x) { return x*x; }
00444 inline bool vnl_math_isnan(vnl_rational const& ){return false;}
00445 inline bool vnl_math_isfinite(vnl_rational const& x){return x.denominator() != 0L;}
00446 
00447 #endif // vnl_rational_h_

Generated on Fri Nov 21 05:06:14 2008 for core/vnl by  doxygen 1.5.1