00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifdef BASIX_HAVE_STDINT_H
00014 #include <stdint.h>
00015 typedef uint64_t lnat;
00016 #else
00017 typedef unsigned long long int lnat;
00018 #endif
00019 #include <numerix/integer.hpp>
00020 #include <algebramix/fft_roots.hpp>
00021
00022 namespace mmx {
00023 #if defined(__GNU_MP__)
00024
00025
00026
00027
00028
00029 static inline nat
00030 mpn_size (const mp_limb_t* src, nat n) {
00031 while (n > 0 && src[n-1] == 0) n--;
00032 return n;
00033 }
00034
00035 void
00036 mpz_base_encode2 (double* dest, nat n,
00037 const mpz_t& src, unsigned long cap) {
00038
00039
00040 VERIFY (cap <= BITS_PER_LIMB, "invalid capacity");
00041 static nat lbpl= log_2 (BITS_PER_LIMB);
00042 mp_limb_t* sd= src->_mp_d;
00043 nat sn= abs (src->_mp_size);
00044 nat i;
00045 unsigned long pos;
00046 unsigned long end= sn << lbpl;
00047 mp_limb_t mask= (((mp_limb_t) 1) << cap) - 1;
00048 double sgn= mpz_sgn (src);
00049
00050
00051
00052 for (i=0, pos=0; pos < end; i++, pos += cap) {
00053 nat index = pos >> lbpl;
00054 nat offset = pos & (BITS_PER_LIMB - 1);
00055 mp_limb_t x= sd[index] >> offset;
00056 if (offset + cap > BITS_PER_LIMB && pos + cap < end && offset != 0)
00057 x += sd[index+1] << (BITS_PER_LIMB - offset);
00058 dest[i]= sgn * ((double) (x & mask));
00059 }
00060 for (; i<n; i++) dest[i]= 0;
00061 }
00062
00063 void
00064 mpz_base_decode2 (mpz_t& dest, const double* src, nat n, unsigned long cap) {
00065 VERIFY (cap <= BITS_PER_LIMB, "invalid capacity");
00066 nat i;
00067 double sgn= 0;
00068 for (i= n-1; i!=((nat) (-1)); i--)
00069 if (abs (src[i]) > 0.5) break;
00070 if (i == ((nat) (-1))) {
00071 mpz_set_si (dest, 0);
00072 return;
00073 }
00074 sgn= sign (src[i]);
00075 static nat lbpl= log_2 (BITS_PER_LIMB);
00076 static mp_limb_t hibit= ((mp_limb_t) 1) << (BITS_PER_LIMB - 1);
00077 mp_limb_t* dd= dest->_mp_d;
00078 nat dn= dest->_mp_alloc;
00079 for (nat i=0; i<dn; i++) dd[i]= 0;
00080 unsigned long pos;
00081 nat extra= (BITS_PER_LIMB == 32? 3: 2);
00082 VERIFY (extra == 3 || BITS_PER_LIMB >= 64, "unsupported architecture");
00083 ASSERT ((dn + 1 - extra) * BITS_PER_LIMB >= n * cap, "oveflow");
00084
00085 for (i=0, pos=0; i<n; i++, pos += cap) {
00086 nat index = pos >> lbpl;
00087 nat offset= pos & (BITS_PER_LIMB - 1);
00088 double f= floor (sgn * src[i] + 0.5);
00089 lnat x= (lnat) abs (f);
00090 mp_limb_t pp[extra];
00091 pp[0]= (mp_limb_t) x;
00092 if (BITS_PER_LIMB == 32) {
00093 pp[1]= (mp_limb_t) ((x >> 16) >> 16);
00094 pp[2]= 0;
00095 }
00096 else pp[1]= 0;
00097 if (offset != 0) mpn_lshift (pp, pp, extra, offset);
00098
00099
00100
00101
00102
00103
00104
00105 if (f > 0) mpn_add_n (dd + index, dd + index, pp, extra);
00106 else mpn_sub_n (dd + index, dd + index, pp, extra);
00107
00108 nat new_index= (pos + cap) >> lbpl;
00109 if (new_index > index && ((dd[index+extra-1] & hibit) != 0))
00110 dd[index+extra]= (mp_limb_t) (-1);
00111 }
00112
00113
00114 dest->_mp_size = mpn_size (dd, dn);
00115 if (sgn < 0) mpz_neg (dest, dest);
00116 }
00117
00118 #endif
00119 }