00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <numerix/integer.hpp>
00014 namespace mmx {
00015 #if defined(__GNU_MP__)
00016
00017 #define ASSERT_RANGE(cond) assert(cond)
00018
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
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
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
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
00090
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
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
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
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
00165
00166
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
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
00231
00232
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
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
00266
00267
00268
00269
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
00280
00281
00282
00283
00284
00285
00286
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
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
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
00314 }
00315
00316
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
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
00370
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
00399
00400
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
00420
00421
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 }