algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/src/base_double.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : base_double.cpp
00004 * DESCRIPTION: Cutting integers into pieces for FFT-multiplication
00005 * COPYRIGHT  : (C) 2008  Joris van der Hoeven
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 #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 * Encoding integers as vectors of doubles of a fixed bitsize
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   // dest: array of n nats
00039   // src: integer to be cut in n pieces of cap bits.
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   //mmout << "sign= " << sgn << "\n";
00050   //for (nat i=0; i<sn; i++)
00051   //mmout << "source " << i << "= " << sd[i] << "\n";
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   //ASSERT ((dn - extra) * BITS_PER_LIMB >= n * cap, "oveflow");
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     //mmout << "Stage " << i << "\n";
00099     //mmout << "  B= " << BITS_PER_LIMB << "\n";
00100     //mmout << "  I= " << index << "\n";
00101     //mmout << "  O= " << offset << "\n";
00102     //mmout << "  f= " << f << "\n";
00103     //mmout << "  x= " << x << "\n";
00104     //mmout << "  p= " << pp[0] << ", " << pp[1] << ", " << pp[2] << "\n";
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     //mmout << "  r= " << dd[index] << ", " << dd[index+1] << ", " << dd[index+2] << "\n";
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   //for (nat i=0; i<dn; i++)
00113   //mmout << "result " << i << "= " << dd[i] << "\n";
00114   dest->_mp_size = mpn_size (dd, dn);
00115   if (sgn < 0) mpz_neg (dest, dest);
00116 }
00117 
00118 #endif
00119 } // namespace mmx
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines