residue.hpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002     
00003     residue.hpp -- Residue representation with dynamically set module.
00004 
00005     This file is a part of the Arageli library.
00006 
00007     Copyright (C) Nikolai Yu. Zolotykh, 1999--2006
00008     Copyright (C) Sergey S. Lyalin, 2006
00009     University of Nizhni Novgorod, Russia
00010 
00011 *****************************************************************************/
00012 
00024 #ifndef _ARAGELI_residue_hpp_
00025 #define _ARAGELI_residue_hpp_
00026 
00027 #include "config.hpp"
00028 
00029 #include <iostream>
00030 #include <sstream>
00031 
00032 #include "_utility.hpp"
00033 #include "factory.hpp"
00034 #include "intalg.hpp"
00035 
00036 #include "std_import.hpp"
00037 
00038 
00039 namespace Arageli
00040 {
00041 
00042 
00043 template <typename T, typename M>
00044 struct residue_config_default
00045 {
00046     static void init (T& x, const M& m) { normalize(x, m); }
00047     static void get_value (const T& x, const M& m) {}
00048     static void before_oper (const T& x, const M& m) {}
00049     static void after_oper (T& x, const M& m) { normalize(x, m); }
00050     static bool is_normal (const T& x, const M& m) { return is_null(m) || is_null(x/m); }
00051     static void normalize (T& x, const M& m) {if(!is_null(m))x = prrem(x, m);}
00052 };
00053 
00054 
00055 // Residue class.
00056 template
00057 <
00058     typename T, typename M = T,
00059     typename Config = residue_config_default<T, M>
00060 >
00061 class residue
00062 {
00063     mutable T value_m;  // resudue value itself
00064     M module_m; // module value
00065     Config config_m;    // configurator
00066 
00067     template <typename T2, typename M2, typename Config2>
00068     friend class residue;
00069 
00070 public:
00071 
00072     typedef T value_type;
00073     typedef M module_type;
00074     typedef Config config_type;
00075 
00077     residue () : value_m(null<T>()), module_m(null<M>()) {}
00078 
00080     template <typename T1>
00081     residue (const T1& x) : value_m(x), module_m(null<M>()) {}
00082 
00083     // Special copy constructor.
00084     template <typename T1>
00085     residue (const residue<T1>& x) : value_m(x.value()), module_m(x.module()) {}
00086 
00087     // Creates residue from the division of x by m.
00088     residue (const T& x, const M& m) : value_m(x), module_m(m)
00089     { config_m.init(value_m, module_m); }
00090 
00091 
00092     residue (const char* s);
00093 
00094 
00096     const T& value () const
00097     {
00098         config_m.get_value(value_m, module_m);
00099         return value_m;
00100     }
00101 
00103     const M& module () const { return module_m; }
00104 
00106     T& value ()
00107     {
00108         config_m.get_value(value_m, module_m);
00109         return value_m;
00110     }
00111 
00113     M& module () { return module_m; }
00114 
00115 
00117     bool is_normal () const { return config_m.is_normal(value_m, module_m); }
00118 
00120     void normalize () const { config_m.normalize(value_m, module_m); }
00121 
00122 
00123     residue operator- () const
00124     {
00125         config_m.before_oper(value_m, module_m);
00126         return residue(-value_m, module_m);
00127     }
00128     
00129     const residue& operator+ () const { return *this; }
00130 
00131     residue& operator++ ()
00132     {
00133         config_m.before_oper(value_m, module_m);
00134         ++value_m;
00135         config_m.after_oper(value_m, module_m);
00136         return *this;
00137     }
00138     
00139     residue& operator-- ()
00140     {
00141         config_m.before_oper(value_m, module_m);
00142         --value_m;
00143         config_m.after_oper(value_m, module_m);
00144         return *this;
00145     }
00146     
00147     residue operator++ (int) { residue t = *this; operator++(); return t; }
00148     residue operator-- (int) { residue t = *this; operator--(); return t; }
00149     
00150     template <typename T1, typename M1, typename Config1>
00151     residue& operator+= (const residue<T1, M1, Config1>& x)
00152     {
00153         ARAGELI_ASSERT_0
00154             (module_m == x.module_m || is_null(x.module_m) || is_null(module_m));
00155         
00156         config_m.before_oper(value_m, module_m);
00157         
00158         value_m += x.value_m;
00159         if(is_null(module_m) && !is_null(x.module_m))
00160             module_m = x.module_m;
00161         
00162         config_m.after_oper(value_m, module_m);
00163         return *this;
00164     }
00165     
00166     template <typename T1, typename M1, typename Config1>
00167     residue& operator-= (const residue<T1, M1, Config1>& x)
00168     {
00169         ARAGELI_ASSERT_0
00170             (module_m == x.module_m || is_null(x.module_m) || is_null(module_m));
00171         
00172         config_m.before_oper(value_m, module_m);
00173         
00174         value_m -= x.value_m;
00175         if(is_null(module_m) && !is_null(x.module_m))
00176             module_m = x.module_m;
00177         
00178         config_m.after_oper(value_m, module_m);
00179         return *this;
00180     }
00181 
00182     template <typename T1, typename M1, typename Config1>
00183     residue& operator*= (const residue<T1, M1, Config1>& x)
00184     {
00185         ARAGELI_ASSERT_0
00186             (module_m == x.module_m || is_null(x.module_m) || is_null(module_m));
00187         
00188         config_m.before_oper(value_m, module_m);
00189         
00190         value_m *= x.value_m;
00191         if(is_null(module_m) && !is_null(x.module_m))
00192             module_m = x.module_m;
00193         
00194         config_m.after_oper(value_m, module_m);
00195         return *this;
00196     }
00197 
00198     template <typename T1, typename M1, typename Config1>
00199     residue& operator/= (const residue<T1, M1, Config1>& x)
00200     {
00201         ARAGELI_ASSERT_0
00202             (module_m == x.module_m || is_null(x.module_m) || is_null(module_m));
00203         
00204         config_m.before_oper(value_m, module_m);
00205         
00206         if(is_null(module_m) && !is_null(x.module_m))
00207             module_m = x.module_m;
00208         
00209         if(is_null(module_m))
00210             value_m /= x.value_m;
00211         else
00212             value_m *= inverse_mod(x.value_m, T1(module_m));    // WARNING! A factory needed.
00213         
00214         config_m.after_oper(value_m, module_m);
00215         return *this;
00216     }
00217 
00218     template <typename T1, typename M1, typename Config1>
00219     residue& operator%= (const residue<T1, M1, Config1>& x)
00220     { return residue(null(value_m), module_m); }
00221 
00222     bool operator! () const { return is_null(value_m); }
00223     operator bool () const { return !!(*this); }
00224 
00225     operator T () const { return value(); }
00226 
00227 };
00228 
00229 
00230 #define ARAGELI_RESIDUE_BINARY_OP(OP, OPASS)                        \
00231     template                                                        \
00232     <                                                               \
00233         typename T1, typename M1, typename Config1,                 \
00234         typename T2, typename M2, typename Config2                  \
00235     >                                                               \
00236     inline residue<T1, M1, Config1> operator OP                     \
00237     (residue<T1, M1, Config1> a, const residue<T2, M2, Config2>& b) \
00238     { return a OPASS b; }
00239 
00240 ARAGELI_RESIDUE_BINARY_OP(+, +=)
00241 ARAGELI_RESIDUE_BINARY_OP(-, -=)
00242 ARAGELI_RESIDUE_BINARY_OP(*, *=)
00243 ARAGELI_RESIDUE_BINARY_OP(/, /=)
00244 ARAGELI_RESIDUE_BINARY_OP(%, %=)
00245 
00246 
00247 #define ARAGELI_RESIDUE_LOGIC_OP(OP)                                \
00248     template                                                        \
00249     <                                                               \
00250         typename T1, typename M1, typename Config1,                 \
00251         typename T2, typename M2, typename Config2                  \
00252     >                                                               \
00253     inline bool operator OP                                         \
00254     (const residue<T1, M1, Config1>& a,                             \
00255         const residue<T2, M2, Config2>& b)                          \
00256     { return a.value() OP b.value(); }                              \
00257                                                                     \
00258     template                                                        \
00259     <                                                               \
00260         typename T1, typename M1, typename Config1,                 \
00261         typename T2                                                 \
00262     >                                                               \
00263     inline bool operator OP                                         \
00264     (const residue<T1, M1, Config1>& a, const T2& b)                \
00265     { return a.value() OP b; }                                      \
00266                                                                     \
00267     template                                                        \
00268     <                                                               \
00269         typename T1,                                                \
00270         typename T2, typename M2, typename Config2                  \
00271     >                                                               \
00272     inline bool operator OP                                         \
00273     (const T1& a, const residue<T2, M2, Config2>& b)                \
00274     { return a OP b.value(); }
00275 
00276 
00277 
00278 ARAGELI_RESIDUE_LOGIC_OP(==)
00279 ARAGELI_RESIDUE_LOGIC_OP(!=)
00280 ARAGELI_RESIDUE_LOGIC_OP(<)
00281 ARAGELI_RESIDUE_LOGIC_OP(<=)
00282 ARAGELI_RESIDUE_LOGIC_OP(>)
00283 ARAGELI_RESIDUE_LOGIC_OP(>=)
00284 
00285 
00286 template                                                        
00287 <                                                               
00288     typename T1, typename M1, typename Config1,                 
00289     typename T2, typename M2, typename Config2                  
00290 >                                                               
00291 inline int cmp                      
00292 (residue<T1, M1, Config1> a, const residue<T2, M2, Config2>& b) 
00293 { return cmp(a.value(), b.value()); }
00294 
00295 
00296 template <typename T, typename M, typename Config>
00297 inline std::ostream& operator<< (std::ostream& out, const residue<T, M, Config>& x)
00298 { return out << x.value() << "(mod " << x.module() << ")"; }
00299 
00300 
00301 template <typename T, typename M, typename Config>
00302 std::istream& operator>> (std::istream& in, residue<T, M, Config>& x)
00303 {
00304     char ch = 0;
00305     in >> ch;
00306     bool brackets = false;
00307     if(ch == '(')brackets = true;
00308     else in.putback(ch);
00309 
00310     T value;
00311     in >> value;
00312 
00313     if(!in)
00314     {
00315         in.clear(std::ios_base::badbit);
00316         return in;
00317     }
00318 
00319     M module;
00320 
00321     if(_Internal::read_literal(in, "("))
00322     {
00323         if(!_Internal::read_literal(in, "mod"))
00324         {
00325             in.clear(std::ios_base::badbit);
00326             return in;
00327         }
00328 
00329         in >> module;
00330 
00331         if(!in)
00332         {
00333             in.clear(std::ios_base::badbit);
00334             return in;
00335         }
00336 
00337         if(!_Internal::read_literal(in, ")"))
00338         {
00339             in.clear(std::ios_base::badbit);
00340             return in;
00341         }
00342     }
00343     else module = null<M>(value);
00344 
00345     if(brackets && !_Internal::read_literal(in, ")"))
00346     {
00347         in.clear(std::ios_base::badbit);
00348         return in;
00349     }
00350 
00351     x = residue<T, M, Config>(value, module);
00352 
00353     return in;
00354 }
00355 
00356 
00357 template <typename T, typename M, typename Config>
00358 residue<T, M, Config>::residue (const char* s)
00359 {
00360     std::istringstream buf(s);
00361     buf >> *this;
00362 }
00363 
00364 
00365 template <typename T, typename M, typename Config>
00366 const residue<T, M, Config>& abs (const residue<T, M, Config>& x)
00367 { return x; }
00368 
00369 
00370 
00371 } // namesapce Arageli
00372 
00373 
00374 //#ifdef ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE
00375 //  #define ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_RESIDUE
00376 //  #include "residue.cpp"
00377 //  #undef  ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_RESIDUE
00378 //#endif
00379 
00380 #endif

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