algebramix_doc 0.3
|
00001 00002 /****************************************************************************** 00003 * MODULE : multiplier.hpp 00004 * DESCRIPTION: Speedups for when several products are done with a same value 00005 * COPYRIGHT : (C) 2008 Gregoire Lecerf 00006 ******************************************************************************* 00007 * This software falls under the GNU general public license and comes WITHOUT 00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details. 00009 * If you don't have this file, write to the Free Software Foundation, Inc., 00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00011 ******************************************************************************/ 00012 00013 #ifndef __MMX__MULTIPLIER__HPP 00014 #define __MMX__MULTIPLIER__HPP 00015 #include <basix/int.hpp> 00016 #include <basix/wrap.hpp> 00017 #include <numerix/modular.hpp> 00018 00019 namespace mmx { 00020 #define TMPL template<typename C> 00021 #define TMPLX template<typename C, typename X> 00022 #define Multiplier multiplier<C> 00023 00025 TMPL 00026 class multiplier { 00027 C rep; 00028 public: 00029 inline C operator * () const { return rep; } 00030 inline multiplier () : rep (0) {} 00031 inline multiplier (const C& s) : rep (s) {} 00032 inline multiplier (const Multiplier& s) : rep (s.rep) {} 00033 inline Multiplier& operator = (const Multiplier& s) { 00034 rep = s.rep; return *this; } 00035 inline bool operator == (const Multiplier& a) const { 00036 return rep == a.rep; } 00037 inline bool operator != (const Multiplier& a) const { 00038 return rep != a.rep; } 00039 template<typename X> static inline void 00040 rmul (X& dest, const Multiplier& s) { dest = dest * s.rep; } 00041 template<typename X> static inline void 00042 lmul (X& dest, const Multiplier& s) { dest = s.rep * dest; } 00043 }; 00044 00045 template<typename TC, typename SC> 00046 struct as_helper <multiplier<TC>,multiplier<SC> > { 00047 static inline multiplier<TC> 00048 cv (const multiplier<SC>& p) { return multiplier<TC> (*p); } 00049 }; 00050 00051 WRAP_WRAPPED_IMPL(TMPL inline,Multiplier) 00052 WRAP_PRINT_IMPL(TMPL inline,Multiplier) 00053 00054 TMPLX inline X 00055 operator * (const X& a, const Multiplier& b) { 00056 X c (a); 00057 Multiplier::rmul (c, b); 00058 return c; } 00059 00060 TMPLX inline X 00061 operator * (const Multiplier& b, const X& a) { 00062 X c (a); 00063 Multiplier::lmul (c, b); 00064 return c; } 00065 00066 TMPLX inline X 00067 operator *= (X& a, const Multiplier& b) { 00068 Multiplier::rmul (a, b); 00069 return a; } 00070 00071 #undef Multiplier 00072 #undef TMPLX 00073 #undef TMPL 00074 00075 /****************************************************************************** 00076 * Multipliers for modulars over hardware int with preinverse 00077 ******************************************************************************/ 00078 00079 template<nat size> 00080 struct modulus_multiplier_int_preinverse_helper { 00081 typedef modulus_maximum_size_int<size> size_helper; 00082 00083 /* 00084 Double size int is available 00085 */ 00086 00087 template <typename C, typename D, nat m> 00088 struct multiplier_helper { 00089 // C and D are unsigned. 00090 static const nat n = 8 * sizeof(C); 00091 00092 static inline void 00093 set (C& dest, const C& src, const C& p, 00094 const C& q, nat r, nat s, nat t) { 00095 (void) t; (void) q; (void) s; (void) t; 00096 if (p == 0) 00097 dest = src; 00098 else 00099 dest = (((D) src) << r) / p; 00100 return; 00101 } 00102 00103 static inline void 00104 mul (C& dest, const C& src, const C& p, nat r, const C& presrc) { 00105 C b = (C) ((((D) dest) * presrc) >> r); 00106 if (m + 1 <= n) { 00107 dest = dest * src - b * p; 00108 if (dest >= p) dest -= p; 00109 return; 00110 } 00111 D d = ((D) dest) * src - ((D) b) * p; 00112 if (d >= p) d -= p; 00113 dest = (C) d; 00114 } 00115 }; 00116 00117 /* 00118 Multiplier when double size int is not available 00119 */ 00120 00121 template <typename C, nat m> 00122 struct multiplier_helper<C, void, m> { 00123 // C is unsigned. 00124 static const nat n = 8 * sizeof(C); 00125 static const nat n2 = 4 * sizeof(C); 00126 typedef long_int_mul_op<C> long_mul; 00127 typedef long_int_lshift_op<C> long_lshift; 00128 typedef long_int_rshift_op<C> long_rshift; 00129 typedef long_int_sub_op<C> long_sub; 00130 typedef long_int_ge_op<C> long_ge; 00131 00132 static inline void 00133 set (C& dest, const C& src, const C& p, 00134 const C& q, nat r, nat s, nat t) { 00135 if (r == 0) dest = 0; // means p = 1 00136 C d0, d1; 00137 long_mul::op (d1, d0, src, q); 00138 if (m+1 <= n) { 00139 long_rshift::op (d1, d0, t+s-r); 00140 dest = d0; 00141 C d = (src << r) - dest * p; 00142 if (d >= p) dest++; 00143 return; 00144 } 00145 long_rshift::op (d1, d0, r-1); 00146 dest = d0; 00147 C e0, e1; 00148 long_mul::op (e1, e0, dest, p); 00149 d0 = src; 00150 d1 = 0; 00151 long_lshift::op (d1, d0, r); 00152 long_sub::op (d1, d0, e1, e0); 00153 if (long_ge::op (d1, d0, 0, p)) { 00154 long_sub::op (d1, d0, 0, p); 00155 dest ++; 00156 if (long_ge::op (d1, d0, 0, p)) { 00157 long_sub::op (d1, d0, 0, p); 00158 dest ++; 00159 } 00160 } 00161 } 00162 00163 static inline void 00164 mul (C& dest, const C& src, const C& p, nat r, const C& presrc) { 00165 C b0, b1; 00166 long_mul::op (b1, b0, dest, presrc); 00167 long_rshift::op (b1, b0, r); 00168 if (m + 1 <= n) { 00169 dest = dest * src - b0 * p; 00170 if (dest >= p) dest -= p; 00171 return; 00172 } 00173 C x0, x1, y0, y1; 00174 long_mul::op (y1, y0, dest, src); 00175 long_mul::op (x1, x0, b0, p); 00176 long_sub::op (y1, y0, x1, x0); 00177 if (long_ge::op (y1, y0, 0, p)) dest = y0-p; 00178 else dest = y0; 00179 } 00180 }; 00181 00182 template<typename C, typename M> static inline void 00183 set (C& dest, const C& src, const M& x) { 00184 static const nat m = size_helper::template maximum_size_helper<C>::value; 00185 typedef typename unsigned_of_helper<C>::type uC; 00186 typedef typename unsigned_int_with_double_size_helper<uC>::type uD; 00187 uC tmp = dest; 00188 multiplier_helper<uC,uD,m>::set (tmp, (uC) src, 00189 (uC) x.p, (uC) x.q, 00190 x.r, x.s, x.t); 00191 dest = tmp; } 00192 00193 template<typename C, typename M> static inline void 00194 mul (C& dest, const C& src, const M& x, const C& presrc) { 00195 static const nat m = size_helper::template maximum_size_helper<C>::value; 00196 typedef typename unsigned_of_helper<C>::type uC; 00197 typedef typename unsigned_int_with_double_size_helper<uC>::type uD; 00198 uC tmp = dest; 00199 multiplier_helper<uC,uD,m>::mul (tmp, (uC) src, 00200 (uC) x.p, x.r, (uC) presrc); 00201 dest = tmp; } 00202 }; 00203 00204 #define Modulus modulus<C, modulus_int_preinverse<size> > 00205 #define Modular modular<Modulus, V> 00206 00207 template<typename C, typename V, nat size> 00208 class multiplier<Modular> { 00209 typedef modulus_multiplier_int_preinverse_helper<size> multiplier_helper; 00210 C rep; 00211 C pre; // pre-computed shared value 00212 public: 00213 inline C operator * () const { return rep; } 00214 inline multiplier<Modular> () : rep (0) { 00215 multiplier_helper::set (pre, rep, Modular::get_modulus ()); } 00216 inline multiplier<Modular> (const Modular& s) : rep (*s) { 00217 multiplier_helper::set (pre, rep, Modular::get_modulus ()); } 00218 inline multiplier<Modular> (const multiplier<Modular>& s) 00219 : rep (s.rep), pre (s.pre) {} 00220 inline multiplier<Modular>& operator = (const multiplier<Modular>& s) { 00221 rep = s.rep; pre = s.pre; return *this; } 00222 inline bool 00223 operator == (const multiplier<Modular>& a) const { 00224 VERIFY (pre == a.pre,"multiplier<Modular>: pre-computed value differ"); 00225 return rep == a.rep; } 00226 inline bool 00227 operator != (const multiplier<Modular>& a) const { 00228 VERIFY (pre != a.pre,"multiplier<Modular>: pre-computed value are equal"); 00229 return rep != a.rep; } 00230 static inline void 00231 rmul (Modular& dest, const multiplier<Modular>& s) { 00232 multiplier_helper::mul (dest.rep, s.rep, 00233 Modular::get_modulus (), s.pre); } 00234 static inline void 00235 lmul (Modular& dest, const multiplier<Modular>& s) { 00236 multiplier_helper::mul (dest.rep, s.rep, 00237 Modular::get_modulus (), s.pre); } 00238 }; 00239 00240 #undef Modulus 00241 #undef Modular 00242 } // namespace mmx 00243 #endif //__MMX__MULTIPLIER__HPP