numbpart.cc

Go to the documentation of this file.
00001 // compute number of partitions of n
00002 // written by Thorsten Reinecke, 1999-12-06
00003 // last change: 2005-06-05
00004 
00018 // implementation is now threadsafe   
00019 
00020 #include <gmp.h>
00021 #include <stdexcept>
00022 #include "utils.H"
00023 #include <cmath>
00024 
00026 namespace numbpart
00027 {
00028 
00029 inline int omega(const int m)
00030 {
00031   return (3*m*m-m)/2;
00032 } 
00033 
00034 class Cnumbpart : private ForbidAssignment
00035 {
00036  // this class can be utilized to provide access to a bunch of
00037  // (possible cached) partition numbers
00038 private:
00039  const int size;
00040  typedef mpz_t* Pmpz_t;
00041  Pmpz_t* const p;
00042  void numbpart_recurse(const int n);
00043 
00044 public:
00045  Cnumbpart(const int n) : size(n+1), p(new Pmpz_t [size])
00046   {
00047     for (int i=0; i<size; ++i) p[i]=NULL;
00048   }
00049  ~Cnumbpart()
00050   {
00051     for (int i=0; i<size; ++i) 
00052      if (p[i]) { mpz_clear(*p[i]); delete p[i]; p[i]=NULL; }
00053     delete [] p;
00054   }
00055  void get_numbpart(mpz_t res, const int n)
00056  {
00057    if (n<0) throw std::invalid_argument("negative argument in numbpart");
00058    if (n>=size) throw std::out_of_range("argument overflows provided range in numbpart");
00059    // if numbpart(n) has not yet been computed, then compute it...
00060    numbpart_recurse(n);
00061    mpz_set(res,*p[n]);
00062  } 
00063 };
00064 
00065 void Cnumbpart::numbpart_recurse(const int n)
00066 {
00067   if (p[n]) return; // value is cached
00068   if (n==0) { p[n]=new mpz_t[1]; mpz_init_set_si(*p[n],1); return; }
00069 
00070   p[n]=new mpz_t[1];
00071   mpz_init(*p[n]);
00072 
00073 #if 0
00074   // this one uses the stack massively!
00075   int m,i;
00076   m=1;
00077   while ((i=n-omega(m))>=0)
00078    {
00079      numbpart_recurse(i);
00080      if (m%2) mpz_add(*p[n],*p[n],*p[i]); else mpz_sub(*p[n],*p[n],*p[i]);
00081      m++;
00082    }
00083   m=1;
00084   while ((i=n-omega(-m))>=0)
00085    {
00086      numbpart_recurse(i);
00087      if (m%2) mpz_add(*p[n],*p[n],*p[i]); else mpz_sub(*p[n],*p[n],*p[i]);
00088      m++;
00089    }
00090 #else
00091   // this consumes less stack space...
00092   int m = static_cast<int>(std::floor( -(1.0/6.0) + std::sqrt((2.0*n/3.0) + (1.0/36.0)) ));
00093   while (omega(-m)<=n) ++m;
00094 
00095   int i=n-omega(m);
00096   if (i>=0)
00097    {
00098      numbpart_recurse(i);
00099      if (m&1) mpz_add(*p[n],*p[n],*p[i]); else mpz_sub(*p[n],*p[n],*p[i]);
00100    }
00101 
00102   while (--m)
00103    {
00104      i=n-omega(m);
00105      numbpart_recurse(i);
00106      if (m&1) mpz_add(*p[n],*p[n],*p[i]); else mpz_sub(*p[n],*p[n],*p[i]);
00107      i-=m; // that is i=n-omega(-m)
00108      numbpart_recurse(i);
00109      if (m&1) mpz_add(*p[n],*p[n],*p[i]); else mpz_sub(*p[n],*p[n],*p[i]);
00110    }
00111 #endif
00112 }
00113 
00114 
00119 void numbpart(mpz_t res, const int n)
00120 {
00121   Cnumbpart capsule(n+1);
00122   capsule.get_numbpart(res,n);
00123 }
00124 
00125 }
00126 
00127 
00128 #if 0
00129 #include <iostream>
00130 int main()
00131 {
00132   using namespace std;
00133   mpz_t res;
00134   mpz_init(res);
00135 
00136   const unsigned int min = 0;
00137   const unsigned int max = 300000;
00138   const unsigned int step = 501;
00139 
00140 #if 0
00141   cout << "Testing numbpart-function:" << endl;
00142   for (unsigned int i=min; i<=max; i+=step)
00143    {
00144      numbpart::numbpart(res,i);
00145      cout << "p(" << i << ") = ";
00146      mpz_out_str(stdout,10,res);
00147      cout << endl;
00148    }
00149 #endif
00150 
00151   cout << "Testing numbpart cached access:" << endl;
00152   numbpart::Cnumbpart capsule(max);
00153   for (unsigned int i=min; i<=max; i+=step)
00154    {
00155      capsule.get_numbpart(res,i);
00156      cout << "p(" << i << ") = ";
00157      mpz_out_str(stdout,10,res);
00158      cout << endl;
00159    }
00160 
00161   mpz_clear(res);
00162 }
00163 #endif

Generated on Wed Nov 7 23:29:25 2007 for Qsieve by  doxygen 1.5.4