rational.cpp

Go to the documentation of this file.
00001 /*********************************************************************
00002     
00003     rational.cpp
00004 
00005     N.Yu.Zolotykh 1999
00006     University of Nizhni Novgorod, Russia
00007 
00008 *********************************************************************/
00009 
00010 #include "config.hpp"
00011 
00012 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00013     defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_RATIONAL)
00014 
00015 #include "rational.hpp"
00016 
00017 
00018 namespace Arageli
00019 {
00020 
00021 
00022 template <typename T>
00023 rational<T>::rational (const char* s)
00024 {
00025     std::istringstream buf(s);
00026     buf >> *this;
00027     if(!buf && !buf.eof())
00028         throw incorrect_string(s);
00029 }
00030 
00031 
00032 template <typename T, typename Ch, typename ChT>
00033 std::basic_ostream<Ch, ChT>& output_default
00034 (
00035     std::basic_ostream<Ch, ChT>& s,
00036     const rational<T>& x,
00037     const Ch* oblique
00038 )
00039 {
00040     //ARAGELI_ASSERT_0(x.is_normal());
00041     
00042     s << x.numerator();
00043     if(!is_unit(x.denominator()))
00044     {
00045         s << oblique;
00046 
00047         if(s.flags() & std::ios_base::showpos)
00048             s << std::noshowpos << x.denominator() << std::showpos;
00049         else
00050             s << x.denominator();
00051     }
00052 
00053     return s;
00054 }
00055 
00056 
00057 template <typename T, typename Ch, typename ChT>
00058 std::basic_istream<Ch, ChT>& input_list
00059 (
00060     std::basic_istream<Ch, ChT>& in,
00061     rational<T>& x,
00062     const Ch* first_bracket,
00063     const Ch* second_bracket,
00064     const Ch* separator
00065 )
00066 {
00067     ARAGELI_ASSERT_0(_Internal::is_not_contains_spaces(first_bracket));
00068     ARAGELI_ASSERT_0(_Internal::is_not_contains_spaces(second_bracket));
00069     ARAGELI_ASSERT_0(_Internal::is_not_contains_spaces(separator));
00070 
00071     if(!_Internal::read_literal(in, first_bracket))
00072     {
00073         in.clear(std::ios_base::failbit);
00074         return in;
00075     }
00076 
00077     T numerator;
00078     in >> numerator;
00079     if(!in && !in.eof())return in;
00080 
00081     if(!_Internal::read_literal(in, separator))
00082     {
00083         in.clear(std::ios_base::failbit);
00084         return in;
00085     }
00086 
00087     T denominator;
00088     in >> denominator;
00089     if(!in && !in.eof())return in;
00090 
00091     if(!_Internal::read_literal(in, second_bracket))
00092     {
00093         in.clear(std::ios_base::badbit);
00094         return in;
00095     }
00096 
00097     x.numerator() = numerator;
00098     x.denominator() = denominator;
00099     x.normalize();
00100 
00101     return in;
00102 }
00103 
00104 
00105 template <typename T, typename Ch, typename ChT>
00106 std::basic_istream<Ch, ChT>& input_default
00107 (
00108     std::basic_istream<Ch, ChT>& s,
00109     rational<T>& x,
00110     const Ch* oblique
00111 )
00112 {
00113     T p, q;
00114     Ch ch = 0;
00115     bool brackets = false;
00116 
00117     s >> ch;
00118     if(ch == '(')   // WARNING!!!
00119         brackets = true;
00120     else
00121         s.putback(ch);
00122 
00123     s >> p;
00124 
00125     if(!s && !s.eof())return s; // error
00126     
00127     if(s.eof())
00128     {
00129         if(brackets && !_Internal::read_literal(s, ")"))
00130             s.clear(std::ios_base::badbit);
00131 
00132         x = p;
00133         return s;
00134     }
00135     
00136     //ch = s.get();
00137     if(_Internal::read_literal(s, oblique))
00138     {
00139         s >> q;
00140         if(!s && !s.eof())return s; // error
00141         x = p;
00142         x /= q;
00143     }
00144     else
00145     {
00146         //s.putback(ch);
00147         x = p;
00148     }
00149 
00150     s.clear();
00151 
00152     if(brackets && !_Internal::read_literal(s, ")"))    // WARNING!!!
00153         s.clear(std::ios_base::badbit);
00154 
00155     return s;
00156 }
00157 
00158 
00159 template <typename T1, typename T2>
00160 rational<T1> operator+
00161 (const rational<T1>& b, const rational<T2>& c)
00162 {
00163     ARAGELI_ASSERT_0(b.is_normal() && c.is_normal());
00164     
00165     rational<T1> a;
00166     a.numerator() = b.numerator() * c.denominator() + c.numerator() * b.denominator();
00167     a.denominator() = b.denominator() * c.denominator();
00168     a.normalize();
00169     return a;
00170 }
00171 
00172 
00173 template <typename T1, typename T2>
00174 rational<T1> operator-
00175 (const rational<T1>& b, const rational<T2>& c)
00176 {
00177     ARAGELI_ASSERT_0(b.is_normal() && c.is_normal());
00178     
00179     rational<T1> a;
00180     a.numerator() = b.numerator() * c.denominator() - c.numerator() * b.denominator();
00181     a.denominator() = b.denominator() * c.denominator();
00182     a.normalize();
00183     return a;
00184 }
00185 
00186 
00187 template <typename T1, typename T2>
00188 rational<T1> operator*
00189 (const rational<T1>& b, const rational<T2>& c)
00190 {
00191     ARAGELI_ASSERT_0(b.is_normal() && c.is_normal());
00192     
00193     rational<T1> a;
00194 
00195     // WARNING! Solution with type conversion is temporal.
00196 
00197     T1 first_gcd  = gcd(b.numerator(), T1(c.denominator()));
00198     T1 second_gcd = gcd(T1(c.numerator()), b.denominator());
00199     a.numerator() = (b.numerator()/first_gcd) * (c.numerator()/second_gcd);
00200     a.denominator() = (b.denominator()/second_gcd) * (c.denominator()/first_gcd);
00201 
00202     if(is_negative(a.denominator()))
00203     {
00204         opposite(&a.numerator());
00205         opposite(&a.denominator());
00206     }
00207 
00208     ARAGELI_ASSERT_1(a.is_normal());
00209 
00210     //a.numerator() = b.numerator() * c.numerator();
00211     //a.denominator() = b.denominator() * c.denominator();
00212     //a.normalize();
00213 
00214     return a;
00215 }
00216 
00217 
00218 template <typename T1, typename T2>
00219 rational<T1> operator/
00220 (const rational<T1>& b, const rational<T2>& c)
00221 {
00222     ARAGELI_ASSERT_0(b.is_normal() && c.is_normal());
00223     
00224     rational<T1> a;
00225 
00226 
00227     // WARNING! Solution with type conversion is temporal.
00228 
00229     T1 first_gcd  = gcd(b.numerator(), T1(c.numerator()));
00230     T1 second_gcd = gcd(T1(c.denominator()), b.denominator());
00231     a.numerator() = (b.numerator()/first_gcd) * (c.denominator()/second_gcd);
00232     a.denominator() = (b.denominator()/second_gcd) * (c.numerator()/first_gcd);
00233 
00234     if(is_negative(a.denominator()))
00235     {
00236         opposite(&a.numerator());
00237         opposite(&a.denominator());
00238     }
00239 
00240     //std::cout << "\np = " << a.numerator() << ", q = " << a.denominator() << std::endl;
00241     ARAGELI_ASSERT_1(a.is_normal());
00242 
00243     //a.numerator() = b.numerator() * c.denominator();
00244     //a.denominator() = b.denominator() * c.numerator();
00245     //a.normalize();
00246 
00247     return a;
00248 }
00249 
00250 
00251 template <typename T>
00252 rational<T>& rational<T>::inverse ()
00253 {
00254     ARAGELI_ASSERT_0(!Arageli::is_null(denominator()));
00255     std::swap(numerator(), denominator());
00256     
00257     if(is_negative(denominator()))
00258     {
00259         Arageli::opposite(&numerator());
00260         Arageli::opposite(&denominator());
00261     }
00262 
00263     return *this;
00264 }
00265 
00266 
00267 template <typename T>
00268 int rational<T>::sign () const
00269 {
00270     ARAGELI_ASSERT_0(is_normal());
00271     return Arageli::sign(numerator());
00272     
00273     //if(is_null())return 0;
00274     //else if(numerator() > TT::null(numerator()))
00279     //  return 1;
00280     //else return -1;
00281 }
00282 
00283 
00284 template <typename T>
00285 void rational<T>::normalize ()
00286 {
00287     T d = gcd(p, q);
00288     p /= d;
00289     q /= d;
00290 
00291     if(is_negative(q))
00292     {
00293         Arageli::opposite(&p);
00294         Arageli::opposite(&q);
00295     }
00296 }
00297 
00298 
00299 template <typename T>
00300 bool rational<T>::is_normal () const
00301 {
00302     return
00303         is_positive(denominator()) &&
00304         is_coprime(numerator(), denominator());
00305 }
00306 
00307 
00308 
00309 template <typename T>
00310 T ifloor (const rational<T>& x)
00311 {
00312     T result = x.numerator() / x.denominator(); // integer devision
00313     if(is_null(x.numerator() % x.denominator()))return result;
00314     else if(sign(x.numerator()) >= 0)return result;
00315     return result - 1;
00316 }
00317 
00318 
00319 template <typename T>
00320 T iceil (const rational<T>& x)
00321 {
00322     T result = x.numerator() / x.denominator(); // integer devision
00323     if(is_null(x.numerator() % x.denominator()))return result;
00324     else if(is_negative(x.numerator()))return result;
00325     return result + 1;
00326 }
00327 
00328 
00329 
00330 } // namespace Arageli
00331 
00332 #else
00333 
00334 #include "rational.hpp"
00335 
00336 namespace Arageli
00337 {
00338 
00339 const char* rational_output_list_first_bracket_default = "(";
00340 const char* rational_output_list_second_bracket_default = ")";
00341 const char* rational_output_list_separator_default = ", ";
00342 const char* rational_input_list_first_bracket_default = "(";
00343 const char* rational_input_list_second_bracket_default = ")";
00344 const char* rational_input_list_separator_default = ",";
00345 const char* rational_output_default_oblique_default = "/";
00346 const char* rational_input_default_oblique_default = "/";
00347 
00348 }
00349 
00350 #endif // #ifndef ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE

Generated on Thu Aug 31 17:38:08 2006 for Arageli by  doxygen 1.4.7