algebramix_doc 0.3
|
00001 00002 /****************************************************************************** 00003 * MODULE : kronecker_gmp.cpp 00004 * DESCRIPTION: Breaking big integers into parts and recomposing them 00005 * COPYRIGHT : (C) 2007 Joris van der Hoeven and 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 #include <numerix/integer.hpp> 00014 namespace mmx { 00015 #if defined(__GNU_MP__) 00016 00017 #define ASSERT_RANGE(cond) assert(cond) 00018 //#define ASSERT_RANGE(cond) VERIFY(cond,"limb out of range") 00019 00020 static inline void 00021 mpn_set (mp_limb_t* dest, const mp_limb_t* src, mp_size_t size) { 00022 mp_size_t i; 00023 for (i=0; i<size; i++) dest[i]= src[i]; 00024 } 00025 00026 template<typename I> static inline void 00027 mpn_get2 (I& dest, const mp_limb_t* src, unsigned long n, 00028 unsigned long beg, unsigned long end) { 00029 // write bits of src from index beg to end-1 into dest 00030 typedef typename unsigned_of_helper<I>::type U; 00031 dest= 0; 00032 if (end <= beg) return; 00033 const xnat shift_l= bit_size (BITS_PER_LIMB) - 1; 00034 const mp_limb_t ceil_l= (- (mp_limb_t) 1) << shift_l; 00035 const mp_limb_t mod_l= (- (mp_limb_t) 1) - ceil_l; 00036 end= min (beg + 8 * sizeof (I), min (end, BITS_PER_LIMB * n)); 00037 unsigned long pos= beg; 00038 while (pos < end) { 00039 unsigned long i= pos >> shift_l, o= pos & mod_l; 00040 dest |= ((I) (src[i] >> o)) << (pos - beg); 00041 pos += BITS_PER_LIMB - o; 00042 } 00043 dest &= (((U) -1) >> (8 * sizeof (I) - (end - beg))); 00044 } 00045 00046 static inline void 00047 mpn_get2 (mp_limb_t* dest, const mp_limb_t* src, unsigned long n, 00048 unsigned long beg, unsigned long end) { 00049 // write the bits from beg to end-1 of src into dest 00050 unsigned long i= 0; 00051 while (beg < end) { 00052 mpn_get2 (dest[i], src, n, beg, min (end, beg + BITS_PER_LIMB)); 00053 i++; beg += BITS_PER_LIMB; 00054 } 00055 } 00056 00057 /****************************************************************************** 00058 * Encoding a polynomial of integers using Kronecker's method 00059 ******************************************************************************/ 00060 00061 static inline void 00062 mpn_lshift_bis (mp_limb_t* dest, mp_size_t dest_size, 00063 const mp_limb_t* src , mp_size_t src_size, 00064 unsigned int count) 00065 { 00066 assert (dest_size >= src_size && dest_size > 0); 00067 if (dest_size == src_size) { 00068 if (count == 0) mpn_set (dest, src, src_size); 00069 else (void) mpn_lshift (dest, src, src_size, count); 00070 } 00071 else { 00072 mp_size_t i; 00073 if (src_size == 0) dest[src_size]= 0; 00074 else { 00075 if (count == 0) { 00076 mpn_set (dest, src, src_size); 00077 dest[src_size]= 0; 00078 } 00079 else dest[src_size]= mpn_lshift (dest, src, src_size, count); 00080 } 00081 for (i=src_size+1; i<dest_size; i++) dest[i]= 0; 00082 } 00083 } 00084 00085 void 00086 mpz_encode_kronecker (mpz_t dest, 00087 const mpz_t* src, unsigned long n, unsigned long bits) 00088 { 00089 // src is an array of length n of integers which fit into bits-1 bits. 00090 // We set dest := src[0]+ src[1] 2^{bits} + ... + src[n-1] 2^{(n-1) bits}. 00091 00092 unsigned long i; 00093 mp_size_t dest_size; 00094 mp_size_t cleaned; 00095 mpz_t aux; 00096 int dest_sgn; 00097 00098 while (n>0 && mpz_sgn (src[n-1]) == 0) n--; 00099 mpz_set_si (dest, 0); 00100 if (n == 0) return; 00101 dest_sgn= mpz_sgn (src[n-1]); 00102 00103 mpz_realloc2 (dest, n * bits); 00104 dest_size = dest->_mp_alloc; 00105 cleaned= dest_size; 00106 //mmout << "dest_size= " << dest_size << "\n"; 00107 00108 mpz_init2 (aux, bits + BITS_PER_LIMB); 00109 for (i=n-1; i != ((unsigned long) -1); i--) { 00110 mp_size_t j; 00111 mp_size_t bit = i * bits; 00112 unsigned int shift = bit & (BITS_PER_LIMB-1); 00113 mp_size_t offset = bit / BITS_PER_LIMB; 00114 mp_size_t extra = cleaned - offset; 00115 mp_size_t aux_size= aux->_mp_alloc; 00116 mp_size_t src_ssz = src[i]->_mp_size; 00117 mp_size_t src_size= (src_ssz>0? src_ssz: -src_ssz); 00118 int src_sgn = (src_ssz>=0? 1: -1); 00119 if (aux_size + offset > dest_size) aux_size--; 00120 /* 00121 mmout << "Step " << i << "\n"; 00122 mmout << " bit = " << bit << "\n"; 00123 mmout << " shift = " << shift << "\n"; 00124 mmout << " offset = " << offset << "\n"; 00125 mmout << " extra = " << extra << "\n"; 00126 mmout << " aux_size= " << aux_size << "\n"; 00127 mmout << " src_size= " << src_size << "\n"; 00128 mmout << " dest_sgn= " << dest_sgn << "\n"; 00129 mmout << " src_sgn = " << src_sgn << "\n"; 00130 */ 00131 00132 // ASSERT_RANGE (aux->_mp_alloc >= aux_size); // Useless, GL. 00133 mpn_lshift_bis (aux->_mp_d, aux_size, src[i]->_mp_d, src_size, shift); 00134 if (src_sgn == dest_sgn) { 00135 for (j=0; j<extra; j++) 00136 dest->_mp_d[j+offset]= aux->_mp_d[j]; 00137 if (aux_size > extra) { 00138 ASSERT_RANGE (dest->_mp_alloc >= cleaned + aux_size - extra); 00139 mpn_add_n (dest->_mp_d + cleaned, dest->_mp_d + cleaned, 00140 aux->_mp_d + extra, aux_size - extra); 00141 } 00142 } 00143 else { 00144 ASSERT_RANGE (dest->_mp_alloc >= offset + extra); 00145 for (j=0; j<extra; j++) 00146 dest->_mp_d[j+offset]= 0; 00147 ASSERT_RANGE (dest->_mp_alloc >= dest_size); 00148 mpn_sub (dest->_mp_d + offset, 00149 dest->_mp_d + offset, dest_size - offset, 00150 aux->_mp_d, aux_size); 00151 } 00152 cleaned= offset; 00153 } 00154 mpz_clear (aux); 00155 00156 while (dest->_mp_d[dest_size-1] == 0) dest_size--; 00157 dest->_mp_size= (dest_sgn>0? dest_size: -dest_size); 00158 } 00159 00160 template<typename I> static inline void 00161 mpz_encode_kronecker_uint (mpz_t dest, 00162 const I* src, unsigned long n, unsigned long bits) 00163 { 00164 // src is an array of length n of unsigned hardware integers which fit 00165 // into e bits. We set dest := src[0]+ src[1] 2^{bits} + ... + 00166 // src[n-1] 2^{(n-1) bits}. 00167 while (n > 0 && src[n-1] == 0) n--; 00168 mpz_set_si (dest, 0); 00169 if (n == 0) return; 00170 static const xnat k= 8 * sizeof (I); 00171 const xnat shift_k= bit_size (k) - 1; 00172 const unsigned long ceil_k= (- (unsigned long) 1) << shift_k; 00173 const unsigned long mod_k= (- (unsigned long) 1) - ceil_k; 00174 mpz_realloc2 (dest, (n * bits + k - 1) & ceil_k); 00175 for (unsigned long i= 0; i < (unsigned long) dest->_mp_alloc; i++) 00176 dest->_mp_d[i]= 0; 00177 unsigned long pos= 0, j, o; 00178 I* aux= (I*) (void*) dest->_mp_d; 00179 for (unsigned long i= 0; i < n; i++, pos += bits) { 00180 j= pos >> shift_k, o= pos & mod_k; 00181 aux[j ] |= src[i] << o; 00182 if (o != 0) aux[j + 1] |= src[i] >> (k - o); 00183 } 00184 dest->_mp_size= dest->_mp_alloc; 00185 while (dest->_mp_size > 0 && dest->_mp_d[dest->_mp_size - 1] == 0) 00186 dest->_mp_size--; 00187 } 00188 00189 #define IMPLEMENTATION_HELPER(I) \ 00190 void mpz_encode_kronecker (mpz_t dest, \ 00191 const I* src, unsigned long n, \ 00192 unsigned long bits) { \ 00193 mpz_encode_kronecker_uint (dest, src, n, bits); } 00194 00195 IMPLEMENTATION_HELPER(unsigned char) 00196 IMPLEMENTATION_HELPER(unsigned short) 00197 IMPLEMENTATION_HELPER(unsigned int) 00198 IMPLEMENTATION_HELPER(unsigned long int) 00199 IMPLEMENTATION_HELPER(unsigned long long int) 00200 #undef IMPLEMENTATION_HELPER 00201 00202 /****************************************************************************** 00203 * Decoding a polynomial of integers using Kronecker's method 00204 ******************************************************************************/ 00205 00206 static inline void 00207 mpn_rshift_bis (mp_limb_t* dest, mp_size_t dest_size, 00208 const mp_limb_t* src , mp_size_t src_size, 00209 unsigned int count) 00210 { 00211 assert (dest_size > 0); 00212 if (src_size >= dest_size) { 00213 if (count == 0) mpn_set (dest, src, dest_size); 00214 else (void) mpn_rshift (dest, src, dest_size, count); 00215 } 00216 else { 00217 mp_size_t i; 00218 if (src_size != 0) { 00219 if (count == 0) mpn_set (dest, src, src_size); 00220 else mpn_rshift (dest, src, src_size, count); 00221 } 00222 for (i=src_size; i<dest_size; i++) dest[i]= 0; 00223 } 00224 } 00225 00226 void 00227 mpz_decode_kronecker (mpz_t* dest, unsigned long n, unsigned long bits, 00228 const mpz_t src_bis) 00229 { 00230 // let src be an integer of the form a_0 + ... + a_{n-1} 2^{(n-1) bits}, 00231 // where the a_i are positive or negative integers of at most bits-1 bits. 00232 // On exit, we have dest[i] := a_i for each i. 00233 00234 unsigned long i, src_bit_size; 00235 mp_size_t src_size, aux_size; 00236 int src_sgn; 00237 mpz_t src, aux, tmp; 00238 mp_limb_t mask= (((mp_limb_t) 1) << (bits & (BITS_PER_LIMB-1))) - 1; 00239 if (mask == 0) mask= (mp_limb_t) -1; 00240 mpz_init2 (src, (mpz_size (src_bis) + 1) * BITS_PER_LIMB); 00241 mpz_set (src, src_bis); 00242 ASSERT_RANGE (((long int) src->_mp_alloc) > ((long int) mpz_size (src))); 00243 src->_mp_d[mpz_size (src)]= 0; 00244 00245 /* handle trailing zeros */ 00246 if (n == 0) return; 00247 src_bit_size= mpz_sizeinbase (src, 2); 00248 if (src_bit_size < (n-1) * bits) { 00249 unsigned long new_n= (src_bit_size / bits) + 1; 00250 for (i= new_n; i<n; i++) mpz_set_si (dest[i], 0); 00251 n= new_n; 00252 } 00253 ASSERT_RANGE (src_bit_size < n*bits); 00254 ASSERT_RANGE (src_bit_size >= (n-1) * bits); 00255 00256 src_size= mpz_size (src) + 1; 00257 src_sgn= mpz_sgn (src); 00258 mpz_init2 (aux, bits + BITS_PER_LIMB); 00259 aux_size= aux->_mp_alloc; 00260 mpz_init2 (tmp, bits + BITS_PER_LIMB); 00261 mpz_set_si (tmp, 1); 00262 mpz_mul_2exp (tmp, tmp, bits); 00263 00264 /* 00265 mmout << "mask\t= " << mask << "\n"; 00266 mmout << "n\t= " << n << "\n"; 00267 mmout << "src_sz\t= " << src_size << "\n"; 00268 mmout << "src_sgn\t= " << src_sgn << "\n"; 00269 mmout << "aux_sz\t= " << aux_size << "\n"; 00270 */ 00271 00272 for (i=0; i<n; i++) { 00273 int dest_sgn = 1; 00274 mp_size_t bit = i * bits; 00275 unsigned int shift = bit & (BITS_PER_LIMB-1); 00276 mp_size_t offset = bit / BITS_PER_LIMB; 00277 00278 /* 00279 mmout << "Stage " << i << "\n"; 00280 mmout << " bit\t= " << bit << "\n"; 00281 mmout << " total\t= " << src_bit_size << "\n"; 00282 mmout << " shift\t= " << shift << "\n"; 00283 mmout << " off\t= " << offset << "\n"; 00284 */ 00285 00286 /* put the raw next coefficient in aux */ 00287 ASSERT_RANGE (aux->_mp_alloc >= aux_size); 00288 mpn_rshift_bis (aux->_mp_d, aux_size, 00289 src->_mp_d+offset, src_size-offset, shift); 00290 ASSERT_RANGE (aux->_mp_alloc >= aux_size); 00291 aux->_mp_d[aux_size-2] &= mask; 00292 aux->_mp_size= aux_size - 1; 00293 while (aux->_mp_size > 0 && aux->_mp_d[aux->_mp_size-1] == 0) 00294 aux->_mp_size--; 00295 00296 /* check whether the next coefficient has a negative sign */ 00297 if (i != n-1) { 00298 unsigned int k= (bits-1) & (BITS_PER_LIMB-1); 00299 mp_size_t l= (bits-1) / BITS_PER_LIMB; 00300 dest_sgn= ((aux->_mp_d[l] & ((mp_limb_t) 1<<k)) == 0? 1: -1); 00301 if (dest_sgn < 0) { 00302 /* in-place update of src in case of a negative sign */ 00303 mp_size_t next_bit = (i+1) * bits; 00304 unsigned int next_shift = next_bit & (BITS_PER_LIMB-1); 00305 mp_size_t next_offset= next_bit / BITS_PER_LIMB; 00306 mp_limb_t plus = ((mp_limb_t) 1) << next_shift; 00307 ASSERT_RANGE (src->_mp_alloc >= src_size); 00308 if (mpn_add (src->_mp_d + next_offset, 00309 src->_mp_d + next_offset, src_size - next_offset, 00310 &plus, 1) != 0) 00311 ASSERT (false, "unexpected carry (mpz_decode_kronecker)"); 00312 } 00313 //mmout << " sgn\t= " << dest_sgn << "\n"; 00314 } 00315 00316 /* put the sign-corrected next coefficient in dest[i] */ 00317 if (dest_sgn >= 0) mpz_set (dest[i], aux); 00318 else mpz_sub (dest[i], tmp, aux); 00319 if (dest_sgn != src_sgn) dest[i]->_mp_size= -dest[i]->_mp_size; 00320 } 00321 00322 mpz_clear (src); 00323 mpz_clear (aux); 00324 mpz_clear (tmp); 00325 } 00326 00327 template<typename I> static inline void 00328 mpz_decode_kronecker_uint (I* dest, unsigned long n, unsigned long bits, 00329 const mpz_t src, 00330 unsigned int e= 8 * sizeof (I)) { 00331 ASSERT (2*e <= bits, "overflow"); 00332 const xnat k= 8 * sizeof (I); 00333 const xnat shift_k= bit_size (k) - 1; 00334 const unsigned long ceil_k= (- (unsigned long) 1) << shift_k; 00335 const unsigned long mod_k= (- (unsigned long) 1) - ceil_k; 00336 unsigned long i= 0, j, o, sz= BITS_PER_LIMB * src->_mp_size, pos= 0; 00337 const I* aux= (I*) (void*) src->_mp_d; 00338 for (; pos + (k << 1) < sz && i < n; i++, pos += bits) { 00339 j= pos >> shift_k, o= pos & mod_k; 00340 if (o == 0) 00341 dest[i]= aux[j] >> o; 00342 else 00343 dest[i]= (aux[j] >> o) | (aux[j+1] << (k - o)); 00344 } 00345 for (; pos < sz && i < n; i++, pos += bits) 00346 mpn_get2 (dest[i], src->_mp_d, src->_mp_size, pos, pos+bits); 00347 for (; i < n; i++) dest[i]= 0; 00348 } 00349 #define IMPLEMENTATION_HELPER(I) \ 00350 void mpz_decode_kronecker (I* dest, unsigned long n, \ 00351 unsigned long bits, const mpz_t src) { \ 00352 mpz_decode_kronecker_uint (dest, n, bits, src); } 00353 00354 IMPLEMENTATION_HELPER(unsigned char) 00355 IMPLEMENTATION_HELPER(unsigned short) 00356 IMPLEMENTATION_HELPER(unsigned int) 00357 IMPLEMENTATION_HELPER(unsigned long int) 00358 IMPLEMENTATION_HELPER(unsigned long long int) 00359 #undef IMPLEMENTATION_HELPER 00360 00361 /****************************************************************************** 00362 * Decoding a polynomial of integers using Kronecker's method 00363 ******************************************************************************/ 00364 00365 template<typename L,typename I> static inline void 00366 _mpz_decode_kronecker_mod_uint (I* dest, 00367 unsigned long n, unsigned long bits, 00368 const mpz_t src, const I& p) { 00369 // Kronecker decoding modulo p in case when L is a hardware integer 00370 // type with at least 'bits' bits. 00371 const xnat k= 8 * sizeof (L); 00372 ASSERT (k >= bits, "overflow"); 00373 const xnat shift_k= bit_size (k) - 1; 00374 const L mask= ((L) -1) >> (k - bits); 00375 const unsigned long ceil_k= (- (unsigned long) 1) << shift_k; 00376 const unsigned long mod_k= (- (unsigned long) 1) - ceil_k; 00377 unsigned long i= 0, j, o, sz= BITS_PER_LIMB * src->_mp_size, pos= 0; 00378 const L* aux= (L*) (void*) src->_mp_d; 00379 for (; pos + (k << 1) < sz && i < n; i++, pos += bits) { 00380 j= pos >> shift_k, o= pos & mod_k; 00381 if (o == 0) 00382 dest[i]= ((aux[j] >> o) & mask) % p; 00383 else 00384 dest[i]= (((aux[j] >> o) | (aux[j+1] << (k - o))) & mask) % p; 00385 } 00386 for (; pos < sz && i < n; i++, pos += bits) { 00387 L tmp; mpn_get2 (tmp, src->_mp_d, src->_mp_size, pos, pos+bits); 00388 dest[i]= tmp % p; 00389 } 00390 for (; i < n; i++) dest[i]= 0; 00391 } 00392 00393 template<typename I> static inline void 00394 _mpz_decode_kronecker_mod_integer (I* dest, unsigned long n, 00395 unsigned long bits, const mpz_t src, 00396 const I& p) 00397 { 00398 // let src be an integer of the form a_0 + ... + a_{n-1} 2^{(n-1) bits}, 00399 // where the a_i are positive or negative integers of at most bits-1 bits. 00400 // On exit, we have dest[i] := a_i mod p for each i. 00401 ASSERT (bit_size (p) <= BITS_PER_LIMB, "overflow"); 00402 const mp_size_t e= (bits + BITS_PER_LIMB - 1) / BITS_PER_LIMB; 00403 unsigned long sz= src->_mp_size * BITS_PER_LIMB, i= 0; 00404 mp_limb_t* aux= mmx_new<mp_limb_t> (2*e); 00405 mp_limb_t* q= aux + e; 00406 for (unsigned long pos= 0; pos < sz && i < n; i++, pos += bits) { 00407 mpn_get2 (aux, src->_mp_d, src->_mp_size, pos, pos + bits); 00408 dest[i]= mpn_divrem_1 (q, 0, aux, e, (mp_limb_t) p); 00409 } 00410 for (; i < n; i++) dest[i]= 0; 00411 mmx_delete<mp_limb_t> (aux, 2*e); 00412 } 00413 00414 template<typename I> static inline void 00415 _mpz_decode_kronecker_mod_integer (I* dest, unsigned long n, 00416 unsigned long bits, const mpz_t src, 00417 const mpz_t p) 00418 { 00419 // let src be an integer of the form a_0 + ... + a_{n-1} 2^{(n-1) bits}, 00420 // where the a_i are positive or negative integers of at most bits-1 bits. 00421 // On exit, we have dest[i] := a_i mod p for each i. 00422 const mp_size_t e= (bits + BITS_PER_LIMB - 1) / BITS_PER_LIMB; 00423 unsigned long sz= src->_mp_size * BITS_PER_LIMB, i= 0; 00424 mp_limb_t* aux= mmx_new<mp_limb_t> (2*e + p->_mp_size); 00425 mp_limb_t* q= aux + e, * r= q + e; 00426 for (unsigned long pos= 0; pos < sz && i < n; i++, pos += bits) { 00427 mpn_get2 (aux, src->_mp_d, src->_mp_size, pos, pos + bits); 00428 mpn_tdiv_qr (q, r, 0, aux, e, p->_mp_d, p->_mp_size); 00429 dest[i]= r[0]; 00430 for (xnat j= 1; j < (xnat) p->_mp_size; j++) 00431 dest[i] |= ((I) r[j]) << (j * BITS_PER_LIMB); 00432 } 00433 for (; i < n; i++) dest[i]= 0; 00434 mmx_delete<mp_limb_t> (aux, 2*e + p->_mp_size); 00435 } 00436 00437 template<typename I> static inline void 00438 mpz_decode_kronecker_mod_int (I* dest, unsigned long n, unsigned long bits, 00439 const mpz_t src, const I& p) { 00440 if (p == 0) { 00441 typedef typename unsigned_of_helper<I>::type U; 00442 mpz_decode_kronecker ((U*) (void*) dest, n, bits, src); 00443 return; 00444 } 00445 if (bits <= 8 * sizeof (unsigned char)) { 00446 typedef unsigned char L; 00447 _mpz_decode_kronecker_mod_uint<L> (dest, n, bits, src, p); 00448 } 00449 else if (bits <= 8 * sizeof (unsigned short int)) { 00450 typedef unsigned short int L; 00451 _mpz_decode_kronecker_mod_uint<L> (dest, n, bits, src, p); 00452 } 00453 else if (bits <= 8 * sizeof (unsigned int)) { 00454 typedef unsigned int L; 00455 _mpz_decode_kronecker_mod_uint<L> (dest, n, bits, src, p); 00456 } 00457 else if (bits <= 8 * sizeof (unsigned long int)) { 00458 typedef unsigned long int L; 00459 _mpz_decode_kronecker_mod_uint<L> (dest, n, bits, src, p); 00460 } 00461 else if (bits <= 8 * sizeof (unsigned long long int)) { 00462 typedef unsigned long long int L; 00463 _mpz_decode_kronecker_mod_uint<L> (dest, n, bits, src, p); 00464 } 00465 else 00466 if (bit_size (p) <= BITS_PER_LIMB) 00467 _mpz_decode_kronecker_mod_integer (dest, n, bits, src, p); 00468 else { 00469 integer _p (p); 00470 _mpz_decode_kronecker_mod_integer (dest, n, bits, src, * _p); } } 00471 00472 #define DECLARE_HELPER(I) \ 00473 void mpz_decode_kronecker_mod (I* dest, unsigned long n, \ 00474 unsigned long bits, const mpz_t src, \ 00475 const I& p) { \ 00476 mpz_decode_kronecker_mod_int (dest, n, bits, src, p); } 00477 DECLARE_HELPER(signed char) 00478 DECLARE_HELPER(unsigned char) 00479 DECLARE_HELPER(short int) 00480 DECLARE_HELPER(unsigned short) 00481 DECLARE_HELPER(int) 00482 DECLARE_HELPER(unsigned int) 00483 DECLARE_HELPER(long int) 00484 DECLARE_HELPER(unsigned long int) 00485 DECLARE_HELPER(long long int) 00486 DECLARE_HELPER(unsigned long long int) 00487 #undef DECLARE_HELPER 00488 00489 #endif // __GNU_MP__ 00490 } // namespace mmx