numerix_doc 0.4
/Users/mourrain/Devel/mmx/numerix/include/numerix/modular_int.hpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : modular_int.hpp
00004 * DESCRIPTION: modulus for modular arithmetic over hardware integers
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__MODULAR_INT__HPP
00014 #define __MMX__MODULAR_INT__HPP
00015 #include <basix/operators.hpp>
00016 #include <basix/int.hpp>
00017 #include <numerix/integer.hpp>
00018 #include <numerix/modular.hpp>
00019 
00020 namespace mmx {
00021 
00025 
00026 #define TMPL template<typename C, typename M>
00027 
00028 /******************************************************************************
00029 * Naive implementation relying on hardware division
00030 ******************************************************************************/
00031 // The modulus 'p' is always taken to be positive
00032 // The modulars are in the range [0, p-1]
00033 
00034 template<nat size>
00035 struct modulus_maximum_size_int {
00036 
00037   template<typename C, bool is_signed>
00038   struct _helper {
00039     static const nat value = (size < 8*sizeof(C) ? size : 8*sizeof(C)-1);
00040   };
00041 
00042   template<typename C>
00043   struct _helper<C, false> {
00044     static const nat value = (size <= 8*sizeof(C) ? size : 8*sizeof(C));
00045   };
00046 
00047   template<typename C>
00048   struct maximum_size_helper {
00049     static const nat value = _helper<C, is_signed_helper<C>::value>::value;
00050     static inline C dyn_value () { return value; }
00051   };
00052 
00053   template<typename C>
00054   struct maximum_value_helper {
00055     static const nat _size = maximum_size_helper<C>::value;
00056     typedef typename unsigned_of_helper<C>::type uC;
00057     static const C value = MMX_SAFE_LEFT_SHIFT_INT (uC, 1, _size) - 1;
00058     static inline C dyn_value () { return value; }
00059   };
00060 };
00061 
00062 template<typename V>
00063 struct modulus_normalization_int_naive : public V {
00064 
00065   template<typename C> static inline bool
00066   normalize (C& p) {
00067     typedef typename unsigned_of_helper<C>::type uC;
00068     static const uC a = MMX_SAFE_LEFT_SHIFT_INT(uC, 1,
00069                          V::template maximum_size_helper<C>::value);
00070     p = abs (p);
00071     if ((uC) p == a || p == 0) { p = a; return true; }
00072     return p <= V::template maximum_value_helper<C>::dyn_value ();
00073   }
00074 };
00075 
00076 template<typename V>
00077 struct modulus_reduction_int_naive : public V {
00078   template<typename C> static inline void 
00079   reduce_mod_core (C& dest, const C& p) {
00080     if (p != 0) dest %= p; }
00081 
00082   template<typename C> static inline void 
00083   reduce_mod_core (C& dest, const C& p, C& carry) {
00084     if (p != 0) { carry= dest / p; dest %= p; }
00085     else carry = 0; }
00086 
00087   TMPL static inline void 
00088   reduce_mod (C& dest, const M& m) {
00089     reduce_mod_core (dest, (C) m.p); }
00090 
00091   TMPL static inline void 
00092   reduce_mod (C& dest, const M& m, C& carry) {
00093     reduce_mod_core (dest, (C) m.p, carry); }
00094 
00095   TMPL static inline void 
00096   reduce_mod (C& dest, const C& s, const M& m) {
00097     dest = s;
00098     reduce_mod_core (dest, (C) m.p); }
00099 
00100   TMPL static inline void 
00101   reduce_mod (C& dest, const C& s, const M& m, C& carry) {
00102     dest = s;
00103     reduce_mod_core (dest, (C) m.p, carry); }
00104 };
00105 
00106 template<typename V>
00107 struct modulus_add_int_naive : public V {
00108 
00109   TMPL static inline void
00110   neg_mod (C& dest, const M& m) {
00111     if (dest != 0) dest = m.p - dest; }
00112 
00113   TMPL static inline void
00114   neg_mod (C& dest, const M& m, C& carry) {
00115     VERIFY (carry == 0 || carry == 1, "unexpected large carry");
00116     if (dest != 0 || carry != 0) { dest= m.p - dest - carry; carry= 1; } }
00117 
00118   TMPL static inline void
00119   neg_mod (C& dest, const C& s, const M& m) {
00120     if (s != 0) dest = m.p - s; else dest = s; }
00121 
00122   TMPL static inline void
00123   neg_mod (C& dest, const C& s, const M& m, C& carry) {
00124     VERIFY (carry == 0 || carry == 1, "unexpected large carry");
00125     if (s != 0 || carry != 0) { dest= m.p - s - carry; carry= 1; }
00126     else dest= 0; }
00127 
00128   template<typename C> static inline void
00129   add_mod_without_overflow (C& dest, const C& s, const C& p) {
00130     dest += s;
00131     if (dest >= p) dest -= p; }
00132 
00133   template<typename C> static inline void
00134   add_mod_without_overflow (C& dest, const C& s, const C& p, C& carry) {
00135     VERIFY (carry == 0 || carry == 1, "unexpected large carry");
00136     dest += s + carry;
00137     if (dest >= p) { dest -= p; carry= 1; } else carry= 0; }
00138 
00139   template<typename C> static inline void
00140   add_mod_with_overflow (C& dest, const C& s, const C& p) {
00141     dest += s;
00142     if (dest < s) { dest -= p; return; }
00143     if (dest >= p) dest -= p; }
00144 
00145   template<typename C> static inline void
00146   add_mod_with_overflow (C& dest, const C& s, const C& p, C& carry) {
00147     VERIFY (carry == 0 || carry == 1, "unexpected large carry");
00148     dest += s + carry;
00149     if (dest < s || dest >= p) { dest -= p; carry= 1; }
00150     else carry= 0; }
00151 
00152   // Signed integer involve no overflow
00153   template<typename C, bool b> 
00154   struct add_mod_helper {
00155     static inline void
00156     op (C& dest, const C& s, const C& p) {
00157       typedef typename unsigned_of_helper<C>::type uC;
00158       uC t = dest, up = p, us = s;
00159       add_mod_without_overflow (t, us, up);
00160       dest = t; }
00161     static inline void
00162     op (C& dest, const C& s, const C& p, C& carry) {
00163       typedef typename unsigned_of_helper<C>::type uC;
00164       uC t = dest, up = p, us = s, ucarry= carry;
00165       add_mod_without_overflow (t, us, up, ucarry);
00166       dest = t; carry= ucarry; }
00167   };
00168 
00169   // Unsigned integer can cause overflow
00170   template<typename C> 
00171   struct add_mod_helper<C,false> {
00172     static inline void
00173     op (C& dest, const C& s, const C& p) {
00174       if (V::template maximum_size_helper<C>::value >= 8*sizeof(C))
00175         add_mod_with_overflow (dest, s, p);
00176       else
00177         add_mod_without_overflow (dest, s, p); }
00178     static inline void
00179     op (C& dest, const C& s, const C& p, C& carry) {
00180       if (V::template maximum_size_helper<C>::value >= 8*sizeof(C))
00181         add_mod_with_overflow (dest, s, p, carry);
00182       else
00183         add_mod_without_overflow (dest, s, p, carry); }
00184   };
00185 
00186   template<typename C> static inline void
00187   add_mod_core (C& dest, const C& s, const C& p) {
00188     add_mod_helper<C,is_signed_helper<C>::value>::op (dest, s, p); }
00189 
00190   template<typename C> static inline void
00191   add_mod_core (C& dest, const C& s, const C& p, C& carry) {
00192     add_mod_helper<C,is_signed_helper<C>::value>::op (dest, s, p, carry); }
00193 
00194   TMPL static inline void
00195   add_mod (C& dest, const C& s, const M& m) {
00196     add_mod_core (dest, s, m.p); }
00197   
00198   TMPL static inline void
00199   add_mod (C& dest, const C& s, const M& m, C& carry) {
00200     add_mod_core (dest, s, m.p, carry); }
00201   
00202   TMPL static inline void
00203   add_mod (C& dest, const C& s1, const C& s2, const M& m) {
00204     dest = s1;
00205     add_mod (dest, s2, m); }
00206   
00207   TMPL static inline void
00208   add_mod (C& dest, const C& s1, const C& s2, const M& m, C& carry) {
00209     dest = s1;
00210     add_mod (dest, s2, m, carry); }
00211   
00212   template<typename C> static inline void
00213   sub_mod_core (C& dest, const C& s, const C& p) {
00214     if (dest < s) dest += p;
00215     dest -= s; }
00216 
00217   template<typename C> static inline void
00218   sub_mod_core (C& dest, const C& s, const C& p, C& carry) {
00219     VERIFY (carry == 0 || carry == 1, "unexpected large carry");
00220     C t = s + carry;
00221     if (t == p || dest < t) { dest += p; carry= 1; } else carry= 0;
00222     dest -= t; }
00223 
00224   TMPL static inline void
00225   sub_mod (C& dest, const C& s, const M& m) {
00226     sub_mod_core (dest, s, m.p); }
00227 
00228   TMPL static inline void
00229   sub_mod (C& dest, const C& s, const M& m, C& carry) {
00230     sub_mod_core (dest, s, m.p, carry); }
00231 
00232   TMPL static inline void
00233   sub_mod (C& dest, const C& s1, const C& s2, const M& m) {
00234     dest = s1;
00235     sub_mod (dest, s2, m); }
00236 
00237   TMPL static inline void
00238   sub_mod (C& dest, const C& s1, const C& s2, const M& m, C& carry) {
00239     dest = s1;
00240     sub_mod (dest, s2, m, carry); }
00241 };
00242  
00243 template<typename V>
00244 struct modulus_mul_int_naive : public V {
00245 
00246   template <typename C, typename D>
00247   struct mul_mod_helper {
00248     static inline void op (C& dest, const C& s, const C& p) {
00249       D a (dest);       
00250       a *= s;
00251       if (p != 0) a %= p;
00252       dest = (C) a;
00253     }
00254     static inline void op (C& dest, const C& s, const C& p, C& carry) {
00255       D a (dest);       
00256       a = a * s + carry;
00257       if (p != 0) { carry= a / p; a %= p; }
00258       dest = (C) a;
00259     }
00260   };
00261 
00262   template <typename C>
00263   struct mul_mod_helper<C, void> {
00264     static const nat half_size = 4 * sizeof (C);
00265     static const nat size = 2 * half_size;
00266     static const C lo_mask = ((C) -1) >> half_size;
00267     static const C hi_mask = ((C) -1) << half_size;
00268     // Let B = (1 << half_size)
00269     static inline C
00270     lo (const C& s) { return s & lo_mask; }
00271     
00272     static inline C
00273     hi (const C& s) { return (s & hi_mask) >> half_size; }
00274 
00275     static inline void
00276     half_lshift_mod(C& dest, const C& p, const C& lo_p,const C& hi_p) {
00277       // p = hi_p * B + lo_p, return (dest * B) % p
00278       // It is required that hi_p != 0
00279       C q = dest / hi_p;
00280       C r = dest - q * hi_p;
00281       q *= lo_p;
00282       q %= p;
00283       dest = r << half_size;
00284       V::sub_mod_core (dest, q, p);
00285     }
00286 
00287     static inline void
00288     half_lshift_mod(C& dest, const C& p, const C& lo_p,const C& hi_p,
00289                     C& carry) {
00290       // p = hi_p * B + lo_p, return (dest * B) % p and (dest * B) / p
00291       // It is required that hi_p != 0
00292       C q = dest / hi_p, c = 0; carry = q;
00293       C r = dest - q * hi_p;
00294       q *= lo_p; carry -= (q / p);
00295       q %= p;
00296       dest = r << half_size;
00297       V::sub_mod_core (dest, q, p, c);
00298       if (c != 0) carry--;
00299     }
00300 
00301     static inline void op (C& dest, const C& s, const C& p) {
00302       C hi_p = hi (p);
00303       if (hi_p) {
00304         C lo_p = lo (p);
00305         C lo_dest = lo (dest);
00306         C lo_s = lo (s);
00307         C hi_dest = hi (dest);
00308         C hi_s = hi (s);
00309         dest = lo_dest * lo_s;
00310         reduce_mod_core (dest, p);
00311         C t = lo_dest * hi_s;
00312         half_lshift_mod (t, p, lo_p, hi_p);
00313         V::add_mod_core (dest, t, p);
00314         t = hi_dest * lo_s;
00315         half_lshift_mod (t, p, lo_p, hi_p);
00316         V::add_mod_core(dest, t, p);
00317         t = hi_dest * hi_s;
00318         half_lshift_mod (t, p, lo_p, hi_p);
00319         half_lshift_mod (t, p, lo_p, hi_p);
00320         V::add_mod_core(dest, t, p);
00321       }
00322       else {
00323         dest *= s;
00324         if (p != 0) dest %= p;
00325       }
00326     }
00327 
00328     static inline void op (C& dest, const C& s, const C& p, C& carry) {
00329       C hi_p = hi (p);
00330       if (hi_p) {
00331         C lo_p = lo (p);
00332         C lo_dest = lo (dest);
00333         C lo_s = lo (s);
00334         C hi_dest = hi (dest);
00335         C hi_s = hi (s);
00336         C c= 0, cc= 0;
00337         dest = lo_dest * lo_s;
00338         reduce_mod_core (dest, p, cc);
00339         C t = lo_dest * hi_s;
00340         half_lshift_mod (t, p, lo_p, hi_p, c); cc += c; c= 0;
00341         V::add_mod_core (dest, t, p, c);       cc += c; c= 0;
00342         t = hi_dest * lo_s;
00343         half_lshift_mod (t, p, lo_p, hi_p, c); cc += c; c= 0;
00344         V::add_mod_core(dest, t, p, c);        cc += c; c= 0;
00345         t = hi_dest * hi_s;
00346         half_lshift_mod (t, p, lo_p, hi_p, c); cc += c << half_size; c= 0;
00347         half_lshift_mod (t, p, lo_p, hi_p, c); cc += c; c= 0;
00348         V::add_mod_core(dest, t, p, c);        cc += c; c= 0;
00349         V::add_mod_core(dest, carry, p, c);    carry = cc + c;
00350       }
00351       else {
00352         dest = dest * s + carry;
00353         if (p != 0) { carry= dest / p; dest %= p; }
00354       }
00355     }
00356   };
00357 
00358   TMPL static inline void
00359   mul_mod (C& dest, const C& s, const M& m) {
00360     if (is_signed_helper<C>::value) {
00361       typedef typename unsigned_of_helper<C>::type uC;
00362       uC t = dest;
00363       mul_mod (t, (uC) s, m);
00364       dest = t;
00365     }
00366     else {
00367       typedef typename unsigned_int_with_double_size_helper<C>::type D;
00368       mul_mod_helper<C,D>::op (dest, s, m.p);
00369     }
00370   }
00371 
00372   TMPL static inline void
00373   mul_mod (C& dest, const C& s, const M& m, C& carry) {
00374     if (is_signed_helper<C>::value) {
00375       typedef typename unsigned_of_helper<C>::type uC;
00376       uC t = dest, ucarry= carry;
00377       mul_mod (t, (uC) s, m, ucarry);
00378       dest = t; carry= ucarry;
00379     }
00380     else {
00381       typedef typename unsigned_int_with_double_size_helper<C>::type D;
00382       mul_mod_helper<C,D>::op (dest, s, m.p, carry);
00383     }
00384   }
00385 
00386   TMPL static inline void
00387   mul_mod (C& dest, const C& s1, const C& s2, const M& m) {
00388     dest = s1;
00389     mul_mod (dest, s2, m); }
00390 
00391   TMPL static inline void
00392   mul_mod (C& dest, const C& s1, const C& s2, const M& m, C& carry) {
00393     dest = s1;
00394     mul_mod (dest, s2, m, carry); }
00395 
00396 };
00397 
00398 template<typename V>
00399 struct modulus_inv_int_naive : public V {
00400 
00401   template<typename C> static void
00402   inv_mod_signed (C& a, const C& p) {
00403     typedef typename unsigned_of_helper<C>::type uC;
00404     typedef typename signed_of_helper<C>::type sC;
00405     sC coa0=0, coa1=1, r0=p, r1=a, q, t;        
00406     if ((p == 0) && (r1 != 0)) {
00407       q = (((uC) r0) - ((uC) r1)) / ((uC) r1) + 1;
00408       t = r0 - q * r1;
00409       r0 = r1;
00410       r1 = t;
00411       t = coa1;
00412       coa1 = coa0 - q * coa1;
00413       coa0 = t;
00414     }
00415     while (r1 != 0) {
00416       q = r0 / r1;
00417       t = r0 - q * r1;
00418       r0 = r1;
00419       r1 = t;
00420       t = coa1;
00421       coa1 = coa0 - q * coa1;
00422       coa0 = t;
00423     }
00424     if (r0 != 1)
00425       ERROR ("inv_mod: argument is not invertible");
00426     a = coa0 < 0 ? p+coa0 : coa0;
00427   }
00428 
00429   template<typename C> static void
00430   inv_mod_unsigned (C& a, const C& p) {
00431     C coa0=0, coa1=1, r0=p, r1=a, q, t; 
00432     bool toggle = true;
00433     if ((p == 0) && (r1 != 0)) {
00434       q = (r0-r1) / r1 + 1;
00435       t = r0 - q * r1;
00436       r0 = r1;
00437       r1 = t;
00438       t = coa1;
00439       coa1 = coa0 - q * coa1;
00440       coa0 = t;
00441       toggle = !toggle;
00442     }
00443     while (r1 != 0) {
00444       q = r0 / r1;
00445       t = r0 - q * r1;
00446       r0 = r1;
00447       r1 = t;
00448       t = coa1;
00449       coa1 = coa0 - q * coa1;
00450       coa0 = t;
00451       toggle = !toggle;
00452     }
00453     if (r0 != 1)
00454       ERROR ("inv_mod: argument is not invertible");
00455     a = (toggle && (coa0 != 0)) ? p+coa0 : coa0;
00456   }
00457 
00458   TMPL static inline void
00459   inv_mod (C& a, const M& m) {
00460     if (V::template maximum_size_helper<C>::value >= 8*sizeof(C))
00461       inv_mod_unsigned(a, m.p);
00462     else
00463       inv_mod_signed(a, m.p); }
00464 
00465   TMPL static inline void
00466   inv_mod (C& dest, const C& s, const M& m) {
00467     dest = s;
00468     inv_mod (dest, m); }
00469 };
00470 
00471 template<typename V>
00472 struct modulus_div_int_naive : public V {
00473 
00474   TMPL static inline void 
00475   div_mod (C& dest, const C& s, const M& m) {
00476     C t = s;
00477     V::inv_mod (t, m);
00478     V::mul_mod (dest, t, m); }
00479 
00480   TMPL static inline void 
00481   div_mod (C& dest, const C& s1, const C& s2, const M& m) {
00482     dest = s1;
00483     div_mod (dest, s2, m); }
00484 };
00485 
00486 template<typename V>
00487 struct modulus_encoding_int_naive : public V {
00488   TMPL static inline void 
00489   encode_mod (C& dest, const C& s, const M& m) {
00490     typedef typename unsigned_of_helper<C>::type uC;
00491     if (sign (s) < 0) {
00492       uC tmp = - ((uC) s);
00493       V::reduce_mod (tmp, m);
00494       dest = (C) (((uC) m.p) - tmp);
00495     }
00496     else
00497       dest = s;
00498       V::reduce_mod (dest, m);
00499   }
00500   TMPL static inline void 
00501   decode_mod (C& dest, const C& s, const M& m) {
00502     (void) m;
00503     dest = s; }
00504 };
00505 
00506 template<int size>
00507 struct modulus_int_naive:
00508   public modulus_encoding_int_naive<
00509          modulus_div_int_naive<
00510          modulus_inv_int_naive<
00511          modulus_mul_int_naive<
00512          modulus_add_int_naive<
00513          modulus_reduction_int_naive<
00514          modulus_normalization_int_naive<
00515          modulus_maximum_size_int<size> > > > > > > > {};
00516 
00517 #undef TMPL
00518 
00519 /******************************************************************************
00520 * Fast implementation relying on hardware product (see doc/texmacs/modular.tm)
00521 ******************************************************************************/
00522 
00523 #define TMPL template<typename C>
00524 
00525 template<typename V>
00526 struct modulus_mul_int_preinverse : public V {
00527 
00528 /*
00529   Dynamic computation of the auxiliaries
00530 */
00531   template <typename C, typename D> 
00532   struct _dynamic_inverse_helper {
00533     typedef typename unsigned_of_helper<C>::type uC;
00534     typedef typename unsigned_of_helper<D>::type uD;
00535     static const nat m = V::template maximum_size_helper<C>::value;
00536     // p must be normalized
00537     static inline uC
00538     op (const uC& p, nat r, nat s, nat t) {
00539       (void) r;
00540       if (p == 1 && s+t == (nat) -1) return 0; // only case when s+t < 0
00541       uD loc_p = (p == 0) ? ((uD) 1) << m : (uD) ((uC) p);
00542       return (((uD) 1) << (s+t)) / loc_p; }
00543   };
00544   
00545   template <typename C>
00546   struct _dynamic_inverse_helper<C,void> {
00547     static const nat n2 = 4 * sizeof(C);
00548     static const nat n  = 8 * sizeof(C);
00549     static const nat m  = V::template maximum_size_helper<C>::value;
00550     typedef typename unsigned_of_helper<C>::type uC;
00551     typedef long_int_mul_op<C>    long_mul;
00552     typedef long_int_rshift_op<C> long_rshift;
00553     typedef long_int_sub_op<C>    long_sub;
00554     
00555     static uC
00556     _q0 (const uC& p, nat r, nat s, nat t, nat s0, nat s1) {
00557       // p != 1 or 2
00558       uC q0;
00559       if (r <= s0)
00560         q0 = (((uC) 1) << (s0+r-1)) / p;
00561       else {
00562         uC p1 = (p == 0) ? ((uC) 1) << s0 : p >> (r-s0);
00563         uC p0 = p & (((uC) -1) >> (n+s0-r));
00564         uC d = ((uC) 1) << s1;
00565         q0 = d / p1;
00566         uC b = (d % p1) << (r-s0);
00567         uC c = q0 * p0;
00568         if (c >= p) { q0--; c -= p; }
00569         if (b < c) q0--;
00570       }
00571       return q0;
00572     }
00573     
00574     static uC
00575     op (const uC& p, nat r, nat s, nat t) {
00576       // If p is 1 or 2 then s0 == 0.
00577       // p must be normalized.
00578       if (p == 1) {
00579         if (m+2 <= n) return 2;
00580         if (m+1 <= n) return 1;
00581         return 0;
00582       }
00583       if (p == 2) {
00584         if (m+2 <= n) return 4;
00585         if (m+1 <= n) return 2;
00586         return 1;
00587       }
00588       nat s0 = (s+t-(r-1)) >> 1;
00589       nat s1 = 2*s0 - 1;
00590       uC q0 = _q0 (p, r, s, t, s0, s1);
00591       uC a0 = 0, a1 = 0;
00592       long_mul::op (a1, a0, q0 * q0, p);
00593       if (long_rshift::op_b (a1, a0, r)) a0++;
00594       uC c = (q0 << s0) - a0;
00595       uC d;
00596       if (m+1 <= n || s1+r <= n) {
00597         if (s1+r-1 >= n) d = 0; else d = (((uC) 1) << (s1+r-1));
00598         d -= c*p;
00599         if (d >= p) { c++; d-=p; }
00600       }
00601       else {
00602         uC d1, e0, e1;
00603         long_mul::op (e1, e0, c, p);
00604         d = 0;
00605         d1 = ((uC) 1) << (s1+r-1-n);
00606         long_sub::op (d1, d, e1, e0);
00607         if ((d1 != 0) || (d >= p)) { c++; d-=p; }
00608       }
00609       uC d2 = d << 1;
00610       c <<= 1;
00611       if ((d2 >= p) || (d2 < d)) { c++; d = d2-p; } else d = d2;
00612       if (s1+1 == s+t-(r-1)) return c;
00613       d2 = d << 1;
00614       c <<= 1;
00615       if ((d2 >= p) || (d2 < d)) c++;
00616       return c;
00617     }
00618   };
00619   
00620   TMPL static inline nat
00621   dyn_r (const C& p) {
00622     typedef typename unsigned_of_helper<C>::type uC;
00623     static const nat m = V::template maximum_size_helper<C>::value;
00624     C abs_p = abs (p);
00625     nat r = bit_size (abs_p);
00626     return (r == 0) ? m : ( (uC) abs_p == (((uC) 1) << (r-1)) ? r-1 : r );
00627   }
00628 
00629   TMPL static inline nat
00630   dyn_s (const C& p, nat r) {
00631     static const nat m = V::template maximum_size_helper<C>::value;
00632     return m+2 <= 8 * sizeof(C) ? r-2 : r-1;
00633   }
00634 
00635   TMPL static inline nat
00636   dyn_t (const C& p, nat r) {
00637     static const nat n = 8 * sizeof(C);
00638     static const nat m = V::template maximum_size_helper<C>::value;
00639     return (m+2 <= n) ? r+3 : ((m+1 <= n) ? r+1 : r);
00640   }
00641 
00642   TMPL static inline C
00643   dyn_q (const C& p, nat r, nat s, nat t) {
00644     typedef typename unsigned_of_helper<C>::type uC;
00645     typedef typename unsigned_int_with_double_size_helper<C>::type D;
00646     return _dynamic_inverse_helper<C,D>::op ((uC) p, r, s, t);
00647   }
00648 
00649 /*
00650   Static computation of the auxiliaries
00651 */
00653   template<typename C, C p>
00654   struct auxiliaries_helper {
00655     static const nat m = V::template maximum_size_helper<C>::value;
00656     typedef typename unsigned_of_helper<C>::type uC;
00657     typedef typename unsigned_int_with_double_size_helper<uC>::type uD;
00658 
00659     static const nat n2= 4*sizeof(C);
00660     static const nat n = 8*sizeof(C);
00661     static const uC abs_p = (uC) ((p < 0) ? -p : p);
00662     static const uC a  = MMX_SAFE_LEFT_SHIFT_INT(uC,1,m);
00663     static const uC up = (abs_p == 0) ? a : abs_p;
00664     static const nat bitsize = int_bitsize_helper<uC, up>::value;
00665     static const nat _b = (bitsize == 0) ? n : bitsize-1;
00666     static const nat r  = (bitsize == 0) ? n :
00667       ( (up == MMX_SAFE_LEFT_SHIFT_INT(uC,1,_b)) ?
00668         bitsize-1 : bitsize );
00669     static const nat s = (m+2 <= n) ? r-2 : r-1;
00670     static const nat t = (m+2 <= n) ? r+3 : ((m+1 <= n) ? r+1 : r);
00671 
00672     template <typename D, typename Dummy> 
00673     struct _inverse_helper {
00674       static const uD _up = (up == 0) ? ((uD) 1) << m : (uD) up;
00675       static const nat _s = (s+t >= 2*n) ? 2*n : s+t;
00676       static const uD _t  = (uD) (MMX_SAFE_LEFT_SHIFT_INT(uD,1,_s));
00677       static const uC value = (up == 1 && m >= n) ?
00678                               (uC) 0 : (uC) (_t / (uD) _up);
00679       static inline C dyn_value () { return value; }
00680     };
00681 
00682     template <typename Dummy> 
00683     struct _inverse_helper <void, Dummy> {
00684       static inline C dyn_value () { return dyn_q ((C) up, r, s, t); }
00685     };
00686 
00687     static inline C q () {
00688       return _inverse_helper<uD, void>::dyn_value (); }
00689   };
00690 
00691 /*
00692   Modular product when int of double size are available
00693 */
00694 
00695   template <typename C, typename D, nat m>
00696   struct mul_mod_helper {
00697     static const nat n = 8 * sizeof(C);
00698     // C and D are unsigned.
00699     static inline void
00700     op (C& dest, const C& src, const C& p,
00701         const C& q, nat r, nat s, nat t) {
00702       D a (dest);
00703       a *= src;
00704       if (m + 2 <= n) {
00705         C hi_a = a >> s;
00706         C b = (((D) hi_a) * q) >> t;
00707         dest = ((C) a) - b * p;
00708         if (dest >= p) dest -=p;
00709         return;
00710       }
00711       D hi_a = a >> s;
00712       C b = (hi_a * q) >> t;
00713       D c = a - ((D) b) * p;
00714       if (m + 1 <= n) {
00715         if (c >= p) {
00716           dest = c - p;
00717           if (dest >= p)
00718             dest -= p;
00719         }
00720         else
00721           dest = c;
00722         return;
00723       }
00724       if (c >= p) {
00725         c -= p;
00726         if (c >= p) {
00727           c -= p;
00728           if (c >= p) 
00729             c -= p;
00730         }
00731       }
00732       dest = c;
00733     }
00734 
00735     static inline void
00736     op (C& dest, const C& src, const C& p, C& carry,
00737         const C& q, nat r, nat s, nat t) {
00738       D a (dest);
00739       a *= src;
00740       if (m + 2 <= n) {
00741         C hi_a = a >> s;
00742         C b = (((D) hi_a) * q) >> t, c = 0;;
00743         dest = ((C) a) - b * p; 
00744         if (dest >= p) { dest -= p; b++; }
00745         V::add_mod_core (dest, carry, p, c); carry = b + c;
00746         return;
00747       }
00748       D hi_a = a >> s;
00749       C b = (hi_a * q) >> t, z= 0;
00750       D c = a - ((D) b) * p;
00751       if (m + 1 <= n) {
00752         if (c >= p) {
00753           dest = c - p; b++;
00754           if (dest >= p) {
00755             dest -= p; b++; }
00756         }
00757         else
00758           dest = c;
00759         V::add_mod_core (dest, carry, p, z); carry = b + z;
00760         return;
00761       }
00762       if (c >= p) {
00763         c -= p; b++;
00764         if (c >= p) {
00765           c -= p; b++;
00766           if (c >= p) {
00767             c -= p; b++; }
00768         }
00769       }
00770       dest = c;
00771       V::add_mod_core (dest, carry, p, z); carry = b + z;
00772     }
00773   };
00774 
00775 /*
00776   Modular product when int of double size are not available
00777 */
00778 
00779   template <typename C, nat m>
00780   struct mul_mod_helper<C, void, m> {
00781     // C is unsigned.
00782     static const nat n2 = 4 * sizeof(C);
00783     static const nat n  = 8 * sizeof(C);
00784     typedef long_int_mul_op<C>    long_mul;
00785     typedef long_int_rshift_op<C> long_rshift;
00786     typedef long_int_sub_op<C>    long_sub;
00787     typedef long_int_ge_op<C>     long_ge;
00788 
00789     static void
00790     op (C& dest, const C& src, const C& p,
00791         const C& q, nat r, nat s, nat t) {
00792 
00793       C a1, a0, hi_a1, hi_a0;
00794       C tmp = dest;
00795       
00796       long_mul::op (a1, a0, tmp, src);
00797       hi_a1 = a1;
00798       hi_a0 = a0;
00799       long_rshift::op (hi_a1, hi_a0, s);
00800       C b1, b0;
00801       long_mul::op (b1, b0, hi_a0, q);
00802       if (m >= n) {if (hi_a1 != 0) b1 += q;}
00803       if (m+1 <= n) {
00804         if (t >= n)
00805           if (n >= t) b0 = b1 << (n-t); else  b0 = b1 >> (t-n);
00806         else
00807           b0 = (b0 >> t) | (b1 << (n-t));
00808       }
00809       else
00810         long_rshift::op (b1, b0, t);
00811       if (m+2 <= n) {
00812         dest = a0 - b0*p;
00813         dest = min (dest, dest - p);
00814         return;
00815       }
00816       C d1, d0;
00817       long_mul::op (d1, d0, b0, p);
00818       long_sub::op (a1, a0, d1, d0);
00819       if (m+1 <= n) {
00820         if (long_ge::op (a1, a0, 0, p)) {
00821           dest = a0 - p;
00822           if (dest >= p)
00823             dest -=p; }
00824         else dest = a0;
00825         return;
00826       }
00827       if (long_ge::op (a1, a0, 0, p)) {
00828         long_sub::op (a1, a0, 0, p);
00829         if (long_ge::op (a1, a0, 0, p)) {
00830           long_sub::op (a1, a0, 0, p);
00831           if (long_ge::op (a1, a0, 0, p)) 
00832             a0 -= p;
00833         }
00834       }
00835       dest = a0;
00836     }
00837  
00838     static void
00839     op (C& dest, const C& src, const C& p, C& carry,
00840         const C& q, nat r, nat s, nat t) {
00841 
00842       C a1, a0, hi_a1, hi_a0;
00843       C tmp = dest;
00844       
00845       long_mul::op (a1, a0, tmp, src);
00846       hi_a1 = a1;
00847       hi_a0 = a0;
00848       long_rshift::op (hi_a1, hi_a0, s);
00849       C b1, b0, c = 0;
00850       long_mul::op (b1, b0, hi_a0, q);
00851       if (m >= n) {if (hi_a1 != 0) b1 += q;}
00852       if (m+1 <= n) {
00853         if (t >= n)
00854           if (n >= t) b0 = b1 << (n-t); else  b0 = b1 >> (t-n);
00855         else
00856           b0 = (b0 >> t) | (b1 << (n-t));
00857       }
00858       else
00859         long_rshift::op (b1, b0, t);
00860       if (m+2 <= n) {
00861         dest = a0 - b0 * p;
00862         if (dest >= p) { dest -= p; b0++; }
00863         V::add_mod_core (dest, carry, p, c); carry = b0 + c;
00864         return;
00865       }
00866       C d1, d0;
00867       long_mul::op (d1, d0, b0, p);
00868       long_sub::op (a1, a0, d1, d0);
00869       if (m+1 <= n) {
00870         if (long_ge::op (a1, a0, 0, p)) {
00871           dest = a0 - p; b0++;
00872           if (dest >= p) {
00873             dest -=p; b0++; } }
00874         else dest = a0;
00875         V::add_mod_core (dest, carry, p, c); carry = b0 + c;
00876         return;
00877       }
00878       if (long_ge::op (a1, a0, 0, p)) {
00879         long_sub::op (a1, a0, 0, p); b0++;
00880         if (long_ge::op (a1, a0, 0, p)) {
00881           long_sub::op (a1, a0, 0, p); b0++;
00882           if (long_ge::op (a1, a0, 0, p)) {
00883             a0 -= p; b0++; }
00884         }
00885       }
00886       dest = a0;
00887       V::add_mod_core (dest, carry, p, c); carry = b0 + c;
00888     }
00889   };
00890   
00891   template<typename C, typename M> static inline void
00892   mul_mod (C& dest, const C& src, const M& x) {
00893     static const nat m = V::template maximum_size_helper<C>::value;
00894     typedef typename unsigned_of_helper<C>::type uC;
00895     typedef typename unsigned_int_with_double_size_helper<uC>::type uD;
00896     uC tmp = dest;
00897     mul_mod_helper<uC,uD,m>::op (tmp, (uC) src, (uC) x.p,
00898                                  (uC) x.q, x.r, x.s, x.t);
00899     dest = tmp; }
00900 
00901   template<typename C, typename M> static inline void
00902   mul_mod (C& dest, const C& src, const M& x, C& carry) {
00903     static const nat m = V::template maximum_size_helper<C>::value;
00904     typedef typename unsigned_of_helper<C>::type uC;
00905     typedef typename unsigned_int_with_double_size_helper<uC>::type uD;
00906     uC tmp = dest, ucarry = carry;
00907     mul_mod_helper<uC,uD,m>::op (tmp, (uC) src, (uC) x.p, ucarry,
00908                                  (uC) x.q, x.r, x.s, x.t);
00909     dest = tmp; carry = ucarry; }
00910 
00911   template<typename C, typename M> static inline void
00912   mul_mod (C& dest, const C& s1, const C& s2, const M& x) {
00913     dest = s1;
00914     mul_mod (dest, s2, x); }
00915 
00916   template<typename C, typename M> static inline void
00917   mul_mod (C& dest, const C& s1, const C& s2, const M& x, C& carry) {
00918     dest = s1;
00919     mul_mod (dest, s2, x, carry); }
00920 };
00921 
00922 template<nat m>
00923 struct modulus_int_preinverse:
00924   public modulus_encoding_int_naive<
00925          modulus_div_int_naive<
00926          modulus_inv_int_naive<
00927          modulus_mul_int_preinverse<
00928          modulus_add_int_naive<
00929          modulus_reduction_int_naive<
00930          modulus_normalization_int_naive<
00931          modulus_maximum_size_int<m> > > > > > > > {};
00932 
00933 /******************************************************************************
00934 * Specialized modulus
00935 ******************************************************************************/
00936 
00937 template<typename C, nat m>
00938 class modulus <C, modulus_int_preinverse<m> > {
00939 MMX_ALLOCATORS
00940 public:
00941   C p;
00942   C q;
00943   nat r;
00944   nat s;
00945   nat t;
00946   C h; // p >> 1
00947   typedef C base;
00948   typedef modulus_int_preinverse<m> variant;
00949   typedef modulus <C, modulus_int_preinverse<m> > self_type;
00950 
00951   inline C operator * () const { return p; }
00952 
00953   inline modulus () : p (0) {
00954     r = variant::dyn_r (p);
00955     s = variant::dyn_s (p, r);
00956     t = variant::dyn_t (p, r);
00957     q = variant::dyn_q (p, r, s, t);
00958     h = p >> 1;
00959   }
00960 
00961   template<typename X>
00962   inline modulus (const X& x) {
00963     p = (C) x;
00964     ASSERT (variant::normalize (p), "modulus: bad value");
00965     r = variant::dyn_r (p);
00966     s = variant::dyn_s (p, r);
00967     t = variant::dyn_t (p, r);
00968     q = variant::dyn_q (p, r, s, t);
00969     h = p >> 1;
00970   }
00971 
00972   template<typename X, X _p>
00973   inline modulus (const fixed_value<X, _p>& x) {
00974     typedef typename variant::template auxiliaries_helper<C, _p> A;
00975     C loc_p = _p;
00976     ASSERT (variant::normalize (loc_p), "modulus: bad value");
00977     p = A::up;
00978     q = A::q ();
00979     r = A::r;
00980     s = A::s;
00981     t = A::t;
00982     h = p >> 1; }
00983     
00984   inline modulus (const self_type& x) : p (x.p), q (x.q),
00985                                         r (x.r), s (x.s),
00986                                         t (x.t), h (x.h) {}
00987 
00988   inline self_type&
00989   operator = (const self_type& x) {
00990     p = x.p;
00991     q = x.q;
00992     r = x.r;
00993     s = x.s;
00994     t = x.t;
00995     h = x.h;
00996     return *this; }
00997 
00998   inline bool operator == (const self_type& a) const {
00999     return p == a.p; }
01000 
01001   inline bool operator != (const self_type& a) const {
01002     return p != a.p; }
01003 };
01004 
01005 #undef TMPL
01006 
01007 /******************************************************************************
01008 * Helpers specializations for hardware integers
01009 ******************************************************************************/
01010 
01011 // Default variant 
01012 #define Variant modulus_int_preinverse
01013 
01014 template<>
01015 struct modulus_variant_helper<unsigned char> {
01016   typedef Variant<8*sizeof(unsigned char)> MV; };
01017 
01018 template<>
01019 struct modulus_variant_helper<short unsigned int> {
01020   typedef Variant<8*sizeof(short unsigned int)> MV; };
01021 
01022 template<>
01023 struct modulus_variant_helper<unsigned int> {
01024   typedef Variant<8*sizeof(unsigned int)> MV; };
01025 
01026 template<>
01027 struct modulus_variant_helper<long unsigned int> {
01028   typedef Variant<8*sizeof(long unsigned int)> MV; };
01029 
01030 template<>
01031 struct modulus_variant_helper<long long unsigned int> {
01032   typedef Variant<8*sizeof(long long unsigned int)> MV; };
01033 
01034 template<>
01035 struct modulus_variant_helper<char> {
01036   typedef Variant<8*sizeof(char)-1> MV; };
01037 
01038 template<>
01039 struct modulus_variant_helper<signed char> {
01040   typedef Variant<8*sizeof(char)-1> MV; };
01041 
01042 template<>
01043 struct modulus_variant_helper<short int> {
01044   typedef Variant<8*sizeof(short int)-1> MV; };
01045 
01046 template<>
01047 struct modulus_variant_helper<int> {
01048   typedef Variant<8*sizeof(int)-1> MV; };
01049 
01050 template<>
01051 struct modulus_variant_helper<long int> {
01052   typedef Variant<8*sizeof(long int)-1> MV; };
01053 
01054 template<>
01055 struct modulus_variant_helper<long long int> {
01056   typedef Variant<8*sizeof(long long int)-1> MV; };
01057 
01058 #undef Variant
01059 
01060 /******************************************************************************
01061 * Lift and project 
01062 ******************************************************************************/
01063 
01064 #define TMPLVW template<typename V, typename W>
01065 #define Modular(I) modular<modulus<I,V>,W>
01066 #define DECLARE_HELPER(I) \
01067 STYPE_TO_TYPE(TMPLVW,lift_type,Modular(I),integer);     \
01068 TMPLVW inline integer \
01069 lift (const Modular(I)& x) { return integer (*x); } \
01070 TMPLVW \
01071 struct project_helper<Modular(I)> { \
01072   template<typename C> static inline Modular(I) \
01073   op (const C& x) { return Modular(I) (x); } \
01074   static inline Modular(I) \
01075   op (const integer& x) { \
01076     integer p= *Modular(I)::get_modulus (); \
01077     return (x >= 0) ? Modular(I) (as<I> (rem (x, p))) \
01078       : - Modular(I) (as<I> (rem (-x, p))); } \
01079 };
01080 
01081 DECLARE_HELPER(unsigned char)
01082 DECLARE_HELPER(signed char)
01083 DECLARE_HELPER(unsigned short int)
01084 DECLARE_HELPER(signed short int)
01085 DECLARE_HELPER(unsigned int)
01086 DECLARE_HELPER(int)
01087 DECLARE_HELPER(unsigned long int)
01088 DECLARE_HELPER(long int)
01089 DECLARE_HELPER(unsigned long long int)
01090 DECLARE_HELPER(long long int)
01091 #undef DECLARE_HELPER
01092 #undef Modular
01093 #undef TMPLVW
01094 
01095 } // namespace mmx
01096 #endif //__MMX__MODULAR_INT__HPP
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines