numerix_doc 0.4
|
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