00001
00002
00003
00004
00018
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
00037
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
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;
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
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
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;
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