00001
00002
00003
00004
00005
00006
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
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 == '(')
00119 brackets = true;
00120 else
00121 s.putback(ch);
00122
00123 s >> p;
00124
00125 if(!s && !s.eof())return s;
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
00137 if(_Internal::read_literal(s, oblique))
00138 {
00139 s >> q;
00140 if(!s && !s.eof())return s;
00141 x = p;
00142 x /= q;
00143 }
00144 else
00145 {
00146
00147 x = p;
00148 }
00149
00150 s.clear();
00151
00152 if(brackets && !_Internal::read_literal(s, ")"))
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
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
00211
00212
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
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
00241 ARAGELI_ASSERT_1(a.is_normal());
00242
00243
00244
00245
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
00274
00279
00280
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();
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();
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 }
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