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