00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 #ifndef VCSN_ALGEBRA_IMPLEMENTATION_SEMIRING_RATIONAL_NUMBER_HXX
00018 # define VCSN_ALGEBRA_IMPLEMENTATION_SEMIRING_RATIONAL_NUMBER_HXX
00019 
00020 # include <vaucanson/misc/contract.hh>
00021 # include <vaucanson/misc/limits.hh>
00022 # include <cmath>
00023 # include <cstdlib>
00024 
00032 namespace vcsn
00033 {
00034   namespace algebra
00035   {
00036     
00037     inline
00038     RationalNumber::RationalNumber(int num, unsigned int denom):
00039       num_ (num),
00040       denom_ (denom)
00041     {
00042       precondition(denom != 0);
00043       set_result();
00044     }
00045 
00046     inline
00047     RationalNumber::RationalNumber():num_ (0), denom_ (1)
00048     {
00049     }
00050 
00051     
00052     inline
00053     RationalNumber::RationalNumber(const RationalNumber& nb) :
00054       num_ (nb.num_), denom_ (nb.denom_)
00055     {
00056       set_result();
00057     }
00058 
00059 
00060     template <typename T>
00061     RationalNumber::RationalNumber(const T num) : num_ (num),
00062                                                   denom_ (T(1))
00063     {
00064     }
00065 
00066     inline
00067     const int&          RationalNumber::num() const
00068     {
00069       return num_;
00070     }
00071 
00072     inline
00073     const unsigned int& RationalNumber::denom() const
00074     {
00075       return denom_;
00076     }
00077 
00078     inline
00079     RationalNumber&     RationalNumber::set_result(int num,unsigned int denom)
00080     {
00081       const int n = gcd(std::abs(num), denom);
00082       num_ = num/n;
00083       denom_ = denom/n;
00084       return *this;
00085     }
00086 
00087     inline
00088     RationalNumber&     RationalNumber::set_result()
00089     {
00090       const int n = gcd(std::abs(num_), denom_);
00091       num_ /= n;
00092       denom_ /= n;
00093       return *this;
00094     }
00095 
00096     inline
00097     std::ostream&       RationalNumber::print(std::ostream& ostr) const
00098     {
00099       return ostr << num_ << "/" << denom_;
00100     }
00101 
00102     
00103 
00104     inline
00105     RationalNumber
00106     RationalNumber::operator+(const RationalNumber& nb) const
00107     {
00108       const int m = lcm(denom_, nb.denom());
00109 
00110       return RationalNumber(num_ * m / denom_ + nb.num() * m / nb.denom(), m);
00111     }
00112 
00113     inline
00114     RationalNumber
00115     RationalNumber::operator-(const RationalNumber& nb) const
00116     {
00117       const int m = lcm(denom_, nb.denom());
00118 
00119       return RationalNumber(num_ * m / denom_ - nb.num() * m / nb.denom(), m);
00120     }
00121 
00122     inline
00123     RationalNumber
00124     RationalNumber::operator-() const
00125     {
00126       return RationalNumber(-num_, denom_);
00127     }
00128 
00129     inline
00130     RationalNumber
00131     RationalNumber::operator*(const RationalNumber& nb) const
00132     {
00133       return RationalNumber(num_ * nb.num(), denom_ * nb.denom());
00134     }
00135 
00136     inline
00137     RationalNumber
00138     RationalNumber::operator/(const RationalNumber& nb) const
00139     {
00140       if (nb.num() < 0)
00141         return RationalNumber(-num_ * nb.denom(), denom_ * -nb.num());
00142       return RationalNumber(num_ * nb.denom(), denom_ * nb.num());
00143     }
00144 
00145     inline
00146     RationalNumber&     RationalNumber::operator+=(const RationalNumber& nb)
00147     {
00148       const int m = lcm(denom_, nb.denom());
00149       return set_result(num_ * m / denom_ + nb.num() * m / nb.denom(), m);
00150     }
00151 
00152     inline
00153     RationalNumber&     RationalNumber::operator-=(const RationalNumber& nb)
00154     {
00155       const int m = lcm(denom_, nb.denom());
00156       return set_result(num_ * m / denom_ - nb.num() * m / nb.denom(), m);
00157     }
00158 
00159     inline
00160     RationalNumber&     RationalNumber::operator*=(const RationalNumber& nb)
00161     {
00162       return set_result(num_ * nb.num(), denom_ * nb.denom());
00163     }
00164 
00165     inline
00166     RationalNumber&     RationalNumber::operator/=(const RationalNumber& nb)
00167     {
00168       if (nb.num() < 0)
00169         return set_result(-num_ * nb.denom(), denom_ * -nb.num());
00170       return set_result(num_ * nb.denom(), denom_ * nb.num());
00171     }
00172 
00173     inline
00174     bool        RationalNumber::operator<(const RationalNumber& nb) const
00175     {
00176       const int m = lcm(denom_, nb.denom());
00177       int num1 = num_ * (m / denom_);
00178       int num2 = nb.num() * (m / nb.denom());
00179       return num1 < num2;
00180     }
00181 
00182     inline
00183     bool        RationalNumber::operator>(const RationalNumber& nb) const
00184     {
00185       const int m = lcm(denom_, nb.denom());
00186       int num1 = num_ * (m / denom_);
00187       int num2 = nb.num() * (m / nb.denom());
00188       return num1 > num2;
00189     }
00190 
00191     inline
00192     bool        RationalNumber::operator<=(const RationalNumber& nb) const
00193     {
00194       const int m = lcm(denom_, nb.denom());
00195       int num1 = num_ * (m / denom_);
00196       int num2 = nb.num() * (m / nb.denom());
00197       return num1 <= num2;
00198     }
00199 
00200     inline
00201     bool        RationalNumber::operator>=(const RationalNumber& nb) const
00202     {
00203       const int m = lcm(denom_, nb.denom());
00204       int num1 = num_ * (m / denom_);
00205       int num2 = nb.num() * (m / nb.denom());
00206       return num1 >= num2;
00207     }
00208 
00209     inline
00210     bool        RationalNumber::operator==(const RationalNumber& nb) const
00211     {
00212       const int m = lcm(denom_, nb.denom());
00213       int num1 = num_ * (m / denom_);
00214       int num2 = nb.num() * (m / nb.denom());
00215       return num1 == num2;
00216     }
00217 
00218     inline
00219     bool        RationalNumber::operator!=(const RationalNumber& nb) const
00220     {
00221       const int m = lcm(denom_, nb.denom());
00222       int num1 = num_ * (m / denom_);
00223       int num2 = nb.num() * (m / nb.denom());
00224       return num1 != num2;
00225     }
00226 
00227     
00228 
00229     inline
00230     int         RationalNumber::to_int() const
00231     {
00232       precondition(denom_<static_cast<unsigned>(misc::limits<int>::max()));
00233       return num_ / static_cast<int> (denom_);
00234     }
00235 
00236     inline
00237     double      RationalNumber::to_double() const
00238     {
00239       return static_cast<double> (num_) / denom_;
00240     }
00241 
00242     inline
00243     std::ostream& operator<<(std::ostream& ostr, const RationalNumber& nb)
00244     {
00245       return nb.print(ostr);
00246     }
00247 
00248    inline
00249     int gcd(int a, unsigned int b)
00250     {
00251       unsigned n = b;
00252       while (n != 0)
00253         {
00254           int t = a % n;
00255           a = n;
00256           n = t;
00257         }
00258       return a;
00259     }
00260 
00261     inline
00262     int lcm(int a, unsigned int b)
00263     {
00264       int d;
00265       if (!a || !b || !(d = gcd(std::abs(a), b)))
00266         return 0;
00267       int r = a * b / d;
00268 
00269       postcondition_ (r != 0, "Overflow");
00270 
00271       return r;
00272     }
00273   }
00274 }
00275 
00276 namespace std
00277 {
00278   inline
00279   ::vcsn::algebra::RationalNumber
00280   numeric_limits< ::vcsn::algebra::RationalNumber >::min()
00281   {
00282     return
00283       ::vcsn::algebra::RationalNumber (std::numeric_limits<int>::min(), 1);
00284   }
00285 
00286   inline
00287   ::vcsn::algebra::RationalNumber
00288   numeric_limits< ::vcsn::algebra::RationalNumber >::max()
00289   {
00290     return
00291       ::vcsn::algebra::RationalNumber (std::numeric_limits<int>::max(), 1);
00292   }
00293 } 
00294 
00295 #endif // ! VCSN_ALGEBRA_IMPLEMENTATION_SEMIRING_RATIONAL_NUMBER_HXX