algebramix_doc 0.3
|
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