/*1* Author: Jonathan Bober2* Version: .63*4* This program computes p(n), the number of integer partitions of n, using Rademacher's5* formula. (See Hans Rademacher, On the Partition Function p(n),6* Proceedings of the London Mathematical Society 1938 s2-43(4):241-254; doi:10.1112/plms/s2-43.4.241,7* currently at8*9* http://plms.oxfordjournals.org/cgi/content/citation/s2-43/4/24110*11* if you have access.)12*13* We use the following notation:14*15* p(n) = lim_{n --> oo} t(n,N)16*17* where18*19* t(n,N) = sum_{k=1}^N a(n,k) f_n(k),20*21* where22*23* a(n,k) = sum_{h=1, (h,k) = 1}^k exp(\pi i s(h,k) - 2 \pi i h n / k)24*25* and26*27* f_n(k) = \pi sqrt{2} cosh(A_n/(sqrt{3}*k))/(B_n*k) - sinh(C_n/k)/D_n;28*29* where30*31* s(h,k) = \sum_{j=1}^{k-1}(j/k)((hj/k))32*33* A_n = sqrt{2} \pi * sqrt{n - 1/24}34* B_n = 2 * sqrt{3} * (n - 1/24)35* C_n = sqrt{2} * \pi * sqrt{n - 1.0/24.0} / sqrt{3}36* D_n = 2 * (n - 1/24) * sqrt{n - 1.0/24.0}37*38* and, finally, where ((x)) is the sawtooth function ((x)) = {x} - 1/2 if x is not an integer, 0 otherwise.39*40* Some clever tricks are used in the computation of s(h,k), and perhaps at least41* some of these are due to Apostol. (I don't know a reference for this.)42*43* TODO:44*45* -- Search source code for other TODO comments.46*47* OTHER CREDITS:48*49* I looked source code written by Ralf Stephan, currently available at50*51* http://www.ark.in-berlin.de/part.c52*53* while writing this code, but didn't really make use of it, except for the54* function cospi(), currently included in the source (slightly modified), but not55* used.56*57* More useful were notes currently available at58*59* http://www.ark.in-berlin.de/part.pdf60*61* and others at62*63* http://www.math.uwaterloo.ca/~dmjackso/CO630/ptnform1.pdf64*65* Also, it is worth noting that the code for GCD(), while trivial,66* was directly copied from the NTL source code.67*68* Also, Bill Hart made some comments about ways to speed up this computation on the SAGE69* mailing list.70*71* This program is free software; you can redistribute it and/or modify72* it under the terms of the GNU General Public License as published by73* the Free Software Foundation; either version 2 of the License, or74* (at your option) any later version.75*76* This program is distributed in the hope that it will be useful,77* but WITHOUT ANY WARRANTY; without even the implied warranty of78* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the79* GNU General Public License for more details.80*81* You should have received a copy of the GNU General Public License82* along with this program. If not, see <http://www.gnu.org/licenses/>.83*/848586#if defined(__sun) || defined(__CYGWIN__)87extern "C" long double fabsl (long double);88extern "C" long double sinl (long double);89extern "C" long double cosl (long double);90extern "C" long double sqrtl (long double);91extern "C" long double coshl (long double);92extern "C" long double sinhl (long double);93#endif9495#include <stdio.h>96#include <cfloat>97#include <time.h>9899#include <cmath>100#include <cstdlib>101#include <cstring>102103#include <iostream>104#include <iomanip>105#include <limits>106107#include <mpfr.h>108#include <gmp.h>109110using namespace std;111112using std::cout;113using std::endl;114115/*****************************************************************************116*117* We begin be declaring all the constant global variables.118*119****************************************************************************/120121// First, some variables that can be set to have the program122// output some information that might be useful for debugging.123124const bool debug = false; // If true, output some random stuff125126const bool debug_precision = false; // If true, output information that might be useful for127// debugging the precision setting code.128129const bool debugs = false; // If true, output informaiton that might be useful for130// debugging the various s() functions.131const bool debugf = false; // Same for the f() functions.132const bool debuga = false; // Same for the a() functions.133const bool debugt = false; // Same for the t() functions.134135#if FLT_RADIX != 2136#error I don't know what to do when the float radix is not 2.137#endif138// Note - it might be unreasonable to not support a float radix other than139// 2, but apparently gcc doesn't either. See http://gcc.gnu.org/ml/fortran/2006-12/msg00032.html.140141142const unsigned int min_precision = DBL_MANT_DIG; // The minimum precision that we will ever use.143const unsigned int double_precision = DBL_MANT_DIG; // The assumed precision of a double.144145146#if defined(__sparc) || defined(__CYGWIN__) || defined(__FreeBSD__)147// On sparc solaris long double is bad/broken/different, etc. E.g.,148// LDBL_MANT_DIG is 113 rather than 106, which causes all kinds of trouble.149// So we only use double_precision.150const unsigned int long_double_precision = double_precision;151#else152const unsigned int long_double_precision = (LDBL_MANT_DIG == 106) ? double_precision : LDBL_MANT_DIG;153#endif154// The assumed precision of a long double.155// Note: On many systems double_precision = long_double_precision. This is OK, as156// the long double stage of the computation will just be skipped.157//158// NOTE: If long_double_precision > dd_precision, then, again, long doubles159// will not ever be used. It would be nice if this were fixed.160161162// Second, some constants that control the precision at which we compute.163164// When we compute the terms of the Rademacher series, we start by computing with165// mpfr_t variables. But for efficiency we switch to special purpose code when166// we don't need as much precision. These constants control the various167// precision levels at which we switch to different special168// purpose functions.169170// const unsigned int level_one_precision = infinity // We don't actually use this, but if we did it would be infinite.171const unsigned int level_two_precision = long_double_precision;172const unsigned int level_three_precision = long_double_precision;173const unsigned int level_four_precision = long_double_precision;174const unsigned int level_five_precision = double_precision;175176177const long double ld_pi = 3.141592653589793238462643L;178const double d_pi = ld_pi;179180// Third, the rounding mode for mpfr.181const mp_rnd_t round_mode = GMP_RNDN;182183/*****************************************************************************184*185* We are finished declaring constants, and next declare semi-constant186* variables. These are all set just once per call to part(n).187*188* All of these are set in initialize_constants(), and the mpfr_t variables189* are cleared in clear_constants().190*191****************************************************************************/192193mpfr_t mp_one_over_12, mp_one_over_24, mp_sqrt2, mp_sqrt3, mp_pi, half, fourth; // These need to be set at run time194// because we don't know how much precision we will need195// until we know for what n we are computing p(n).196197mpfr_t mp_A, mp_B, mp_C, mp_D; // These "constants" all depend on n, and198double d_A, d_B, d_C, d_D; //199long double ld_A, ld_B, ld_C, ld_D; //200201202/*****************************************************************************203*204* We next declare the variables that actually vary. It is cumbersome to have205* so many global variables, but it is somewhat necessary since we want to call206* the functions mpz_init(), mpq_init(), mpfr_init(), and the corresponding207* clear() functions as little as possible.208*209****************************************************************************/210211mpz_t ztemp1; // These are initialized in the function initialize_mpz_and_mpq_variables(), and212mpq_t qtemps, qtempa, qtempa2; // cleared in the function clear_mpz_and_mpq_variables().213// qtemps is used by q_s() and qtempa and qtempa2() are used by mp_a().214//215// ztemp1 is only used in one function, and the code where is it used is actually unlikely216// to be used for any input, so it should be erased.217218mpfr_t tempa1, tempa2, tempf1, tempf2, temps1, temps2; // These are all initialized by initialize_mpfr_variables(), and cleared by219// clear_mpfr_variables().220// NAMING CONVENTIONS:221//222// -tempa1 and tempa2 are two variables available for use223// in the function mp_a()224//225// -tempf1 and tempf2 are two variables available for use226// in the function mp_f()227//228// -etc...229230mpfr_t tempc1, tempc2; // temp variables used by cospi()231232233/*****************************************************************************234*235* End of Global Variables, beginning of function declarations236*237****************************************************************************/238239//240// A listing of the main functions, in "conceptual" order.241//242243int part(mpz_t answer, unsigned int n);244245static void mp_t(mpfr_t result, unsigned int n); // Compute t(n,N) for an N large enough, and with a high enough precision, so that246// |p(n) - t(n,N)| < .5247248static unsigned int compute_initial_precision(unsigned int n); // computes the precision required to accurately compute p(n)249250static void initialize_constants(unsigned int prec, unsigned int n); // Once we know the precision that we will need, we precompute251// some commonly used constants.252253static unsigned int compute_current_precision(unsigned int n, unsigned int N, unsigned int extra); // Computed the precision required to254// accurately compute the tail of the rademacher series255// assuming that N terms have already been computed.256// This is called after computing each summand, unless257// we have already reached the minimum precision.258//259// Reducing the precision as fast as possible is key to260// fast performance.261262static double compute_remainder(unsigned int n, unsigned int N); // Gives an upper bound on the error that occurs263// when only N terms of the Rademacher series have been264// computed.265//266// This should only be called when we know that compute_current_precision267// will return min_precision. Otherwise the error will be too large for268// it to compute.269270271//272// The following functions are all called in exactly one place, so273// we could ask the compiler to inline everything. Actually making this274// work properly requires changing some compiler options, and doesn't275// provide much improvement, however.276//277278static void mp_f(mpfr_t result, unsigned int k); // See introduction for an explanation of these functions.279static void q_s(mpq_t result, unsigned int h, unsigned int k); //280static void mp_a(mpfr_t result, unsigned int n, unsigned int k); //281282template <class T> static inline T a(unsigned int n, unsigned int k); // Template versions of the above functions for computing with283template <class T> static inline T f(unsigned int k); // low precision. Currently used for computing with qd_real, dd_real,284template <class T> static inline T s(unsigned int h, unsigned int k); // long double, and double.285286287//288// The following are a bunch of "fancy macros" designed so that in the templated code289// for a, for example, when we need to use pi, we just call pi<T>() to get pi to290// the proper precision. The compiler should inline these, so using one of these291// functions is just as good as using a constant, and since these functions are static292// they shouldn't even appear in the object code generated.293294template <class T> static inline T pi(){ return ld_pi; }295296template <class T> static inline T sqrt2() {return sqrt(2.0L);}297298template <class T> static inline T sqrt3() {return sqrt(3.0L);}299300template <class T> static inline T A() {return 1;}301template <> inline double A() {return d_A;}302template <> inline long double A() {return ld_A;}303304template <class T> static inline T B() {return 1;}305template <> inline double B() {return d_B;}306template <> inline long double B() {return ld_B;}307308template <class T> static inline T C() {return 1;}309template <> inline double C() {return d_C;}310template <> inline long double C() {return ld_C;}311312template <class T> static inline T D() {return 1;}313template <> inline double D() {return d_D;}314template <> inline long double D() {return ld_D;}315316template <class T> static inline T pi_sqrt2() {return 1;}317template <> inline double pi_sqrt2() {return d_pi * sqrt(2.0);}318template <> inline long double pi_sqrt2() {return ld_pi * sqrt(2.0L);}319320template <class T> static inline T one_over_12() {return 1;}321template <> inline double one_over_12() {return 1.0/12.0;}322template <> inline long double one_over_12() {return 1.0L/12.0L;}323324// A few utility functions...325326static inline long GCD(long a, long b);327int test(bool longtest = false, bool forever = false); // Runs a bunch of tests to make sure328// that we are getting the right answers.329// Tests are based on a few "known" values that330// have been verified by other programs, and331// also on known congruences for p(n)332333static void cospi (mpfr_t res, mpfr_t x); // Puts cos(pi x) in result. This is not currently334// used, but should be faster than using mpfr_cos,335// according to comments in the file part.c336// mentioned in the introduction.337// test338339static int grab_last_digits(char * output, int n, mpfr_t x); // Might be useful for debugging, but340// don't use it for anything else.341// (See function definition for more information.)342343344int main(int argc, char *argv[]); // This program is mainly meant for inclusion345// in SAGE (or any other program, if anyone346// feels like it). We include a main() function347// anyway, because it is useful to compile348// this as a standalone program349// for testing purposes.350351/***********************************************************************352*353* That should be the end of both function and variable definitions.354*355**********************************************************************/356357// The following function can be useful for debugging in come circumstances, but should not be used for anything else358// unless it is rewritten.359int grab_last_digits(char * output, int n, mpfr_t x) {360// fill output with the n digits of x that occur361// just before the decimal point362// Note: this assumes that x has enough digits and enough363// precision -- otherwise bad things can happen364//365// returns: the number of digits to the right of the decimal point366367char * temp;368mp_exp_t e;369370temp = mpfr_get_str(NULL, &e, 10, 0, x, GMP_RNDN);371372int retval;373374if(e > 0) {375strncpy(output, temp + e - n, n);376retval = strlen(temp + e);377}378else {379for(int i = 0; i < n; i++)380output[i] = '0';381retval = strlen(temp);382}383output[n] = '\0';384385mpfr_free_str(temp);386387return retval;388}389390391392unsigned int compute_initial_precision(unsigned int n) {393// We just want to know how many bits we will need to394// compute to get an accurate answer.395396// We know that397//398// p(n) ~ exp(pi * sqrt(2n/3))/(4n sqrt(3)),399//400// so for now we are assuming that p(n) < exp(pi * sqrt(2n/3))/n,401// so we need pi*sqrt(2n/3)/log(2) - log(n)/log(2) + EXTRA bits.402//403// EXTRA should depend on n, and should be something that ensures404// that the TOTAL ERROR in all computations is < (something small).405// This needs to be worked out carefully. EXTRA = log(n)/log(2) + 3406// is probably good enough, and is convenient...407//408// but we really need:409//410// p(n) < something411//412// to be sure that we compute the correct answer413414unsigned int result = (unsigned int)(ceil(3.1415926535897931 * sqrt(2.0 * double(n)/ 3.0) / log(2))) + 3;415if(debug) cout << "Using initial precision of " << result << " bits." << endl;416417if(result > min_precision) {418return result;419}420421else return min_precision;422423}424425unsigned int compute_current_precision(unsigned int n, unsigned int N, unsigned int extra = 0) {426// Roughly, we compute427//428// log(A/sqrt(N) + B*sqrt(N/(n-1))*sinh(C * sqrt(n) / N) / log(2)429//430// where A, B, and C are the constants listed below. These error bounds431// are given in the paper by Rademacher listed at the top of this file.432// We then return this + extra, if extra != 0. If extra == 0, return with433// what is probably way more extra precision than is needed.434//435// extra should probably have been set by a call to compute_extra_precision()436// before this function was called.437438439// n = the number for which we are computing p(n)440// N = the number of terms that have been computed so far441442// if N is 0, then we can't use the above formula (because we would be443// dividing by 0).444if(N == 0) return compute_initial_precision(n) + extra;445446mpfr_t A, B, C;447mpfr_init2(A, 32);448mpfr_init2(B, 32);449mpfr_init2(C, 32);450451mpfr_set_d(A,1.11431833485164,round_mode);452mpfr_set_d(B,0.059238439175445,round_mode);453mpfr_set_d(C,2.5650996603238,round_mode);454455mpfr_t error, t1, t2;456mpfr_init2(error, 32); // we shouldn't need much precision here since we just need the most significant bit457mpfr_init2(t1, 32);458mpfr_init2(t2, 32);459460mpfr_set(error, A, round_mode); // error = A461mpfr_sqrt_ui(t1, N, round_mode); // t1 = sqrt(N)462mpfr_div(error, error, t1, round_mode); // error = A/sqrt(N)463464465mpfr_sqrt_ui(t1, n, round_mode); // t1 = sqrt(n)466mpfr_mul(t1, t1, C, round_mode); // t1 = C * sqrt(n)467mpfr_div_ui(t1, t1, N, round_mode); // t1 = C * sqrt(n) / N468mpfr_sinh(t1, t1, round_mode); // t1 = sinh( ditto )469mpfr_mul(t1, t1, B, round_mode); // t1 = B * sinh( ditto )470471mpfr_set_ui(t2, N, round_mode); // t2 = N472mpfr_div_ui(t2, t2, n-1, round_mode); // t2 = N/(n-1)473mpfr_sqrt(t2, t2, round_mode); // t2 = sqrt( ditto )474475mpfr_mul(t1, t1, t2, round_mode); // t1 = B * sqrt(N/(n-1)) * sinh(C * sqrt(n)/N)476477mpfr_add(error, error, t1, round_mode); // error = (ERROR ESTIMATE)478479unsigned int p = mpfr_get_exp(error); // I am not 100% certain that this always does the right thing.480// (It should be the case that p is now the number of bits481// required to hold the integer part of the error.)482483484if(extra == 0) {485p = p + (unsigned int)ceil(log(n)/log(2)); // This is a stupid case to fall back on,486// left over from earlier versions of this code.487// It really should never be used.488}489else {490p = p + extra; // Recall that the extra precision should be491// large enough so that the accumulated errors492// in all of the computations that we make493// are not big enough to matter.494}495496if(debug) {497cout << "Error seems to be: ";498mpfr_out_str(stdout, 10, 0, error, round_mode);499cout << endl;500cout.flush();501cout << "Switching to precision of " << p << " bits. " << endl;502}503504mpfr_clear(error);505mpfr_clear(t1);506mpfr_clear(t2);507mpfr_clear(A);508mpfr_clear(B);509mpfr_clear(C);510511512if(p > min_precision) {513return p; // We don't want to return < min_precision.514// Note that when the code that calls this515// function finds that the returned result516// is min_precision, it should stop calling517// this function, since the result won't change518// after that. Also, it should probably switch519// to computations with doubles, and should520// start calling compute_remainder().521}522return min_precision;523}524525int compute_extra_precision(unsigned int n, double error = .25) {526// Return the number of terms of the Rachemacher series that527// we will need to compute to get a remainder of less than error528// in absolute value, and then return the extra precision529// that will guarantee that the accumulated error after computing530// that number of steps will be less than .5 - error.531//532// How this works:533// We first need to figure out how many terms of the series we are going to534// need to compute. That is, we need to know how large k needs to be535// for compute_remainder(n,k) to return something smaller than error. There536// might be a clever way to do this, but instead we just keep calling537// compute_current_precision() until we know that the error will be538// small enough to call compute_remainder(). Then we just call compute_remainder()539// until the error is small enough.540//541// Now that we know how many terms we will need to compute, k, we compute542// the number of bits required to accurately store (.5 - error)/k. This ensures543// that the total error introduced when we add up all k terms of the sum544// will be less than (.5 - error). This way, if everything else works correctly,545// then the sum will be within .5 of the correct (integer) answer, and we546// can correctly find it by rounding.547unsigned int k = 1;548for( ; compute_current_precision(n,k,0) > double_precision; k += 100) {549}550551for( ; compute_remainder(n, k) > error ; k += 100) {552}553if(debug_precision) {554cout << "To compute p(" << n << ") we will add up approximately " << k << " terms from the Rachemacher series." << endl;555}556int bits = (int)((log(k/(.5 - error)))/log(2)) + 5; // NOTE: reducing the number of bits by 3 here is known to cause errors557// Why the extra 5 bits? Anytime we call a function, eg mp_a(),558// we end up doing a bunch of arithmetic operations, and if559// we want the result of those operations to be accurate560// within (.5 - error)/k, then we need that function to use561// a slightly higher working precision, which should be562// independent of n.563// TODO:564// Extensive trial and error has found 3 to be the smallest value565// that doesn't seem to produce any wrong answers. Thus, to566// be safe, we use 5 extra bits.567// (Extensive trial and error means compiling this file to get568// a.out and then running './a.out testforever' for a few hours.)569570571572573return bits;574}575576double compute_remainder(unsigned int n, unsigned int N) {577// This computes the remainer left after N terms have been computed.578// The formula is exactly the same as the one used to compute the required579// precision, but once we know the necessary precision is small, we can580// call this function to determine the actual error (rather than the precision).581//582// Generally, this is only called once we know that the necessary583// precision is <= min_precision, because then the error is small584// enough to fit into a double, and also, we know that we are585// getting close to the correct answer.586587double A = 1.11431833485164;588double B = 0.059238439175445;589double C = 2.5650996603238;590double result;591result = A/sqrt(N) + B * sqrt(double(N)/double(n-1))*sinh(C * sqrt(double(n))/double(N));592return result;593}594595596void initialize_mpfr_variables(unsigned int prec) {597//598// Clear and initialize some "temp" variables that are used in the computation of various functions.599//600// We do this in this auxilliary function (and endure the pain of601// the extra global variables) so that we only have to initialize/clear602// these variables once every time the precision changes.603//604// NAMING CONVENTIONS:605//606// -tempa1 and tempa2 are two variables available for use607// in the function mp_a()608//609// -tempf1 and tempf2 are two variables available for use610// in the function mp_f()611//612// -etc...613//614// NOTE: Calls to this function must be paired with calls to clear_mpfr_variables()615616mpfr_init2(tempa1, prec);617mpfr_init2(tempa2, prec);618mpfr_init2(tempf1, prec);619mpfr_init2(tempf2, prec);620mpfr_init2(temps1, prec);621mpfr_init2(temps2, prec);622mpfr_init2(tempc1, prec);623mpfr_init2(tempc2, prec);624}625626void clear_mpfr_variables() {627mpfr_clear(tempa1);628mpfr_clear(tempa2);629mpfr_clear(tempf1);630mpfr_clear(tempf2);631mpfr_clear(temps1);632mpfr_clear(temps2);633634mpfr_clear(tempc1);635mpfr_clear(tempc2);636}637638639void initialize_constants(unsigned int prec, unsigned int n) {640// The variables mp_A, mp_B, mp_C, and mp_D are used for641// A_n, B_n, C_n, and D_n listed at the top of this file.642//643// They depend only on n, so we compute them just once in this function,644// and then use them many times elsewhere.645//646// Also, we precompute some extra constants that we use a lot, such as647// sqrt2, sqrt3, pi, 1/24, 1/12, etc.648//649// NOTE: Calls to this function must be paired with calls to clear_constants()650static bool init = false;651mp_prec_t p = prec;652653mpfr_init2(mp_one_over_12,p); mpfr_init2(mp_one_over_24,p); mpfr_init2(mp_sqrt2,p); mpfr_init2(mp_sqrt3,p); mpfr_init2(mp_pi,p);654mpfr_init2(mp_A,p); mpfr_init2(mp_B,p); mpfr_init2(mp_C,p); mpfr_init2(mp_D,p); mpfr_init2(fourth, p); mpfr_init2(half, p);655656init = true;657658mpfr_set_ui(mp_one_over_12, 1, round_mode); // mp_one_over_12 = 1/12659mpfr_div_ui(mp_one_over_12, mp_one_over_12, 12, round_mode); //660661mpfr_set_ui(mp_one_over_24, 1, round_mode); // mp_one_over_24 = 1/24662mpfr_div_ui(mp_one_over_24, mp_one_over_24, 24, round_mode); //663664mpfr_set_ui(half, 1, round_mode); //665mpfr_div_ui(half, half, 2, round_mode); // half = 1/2666mpfr_div_ui(fourth, half, 2, round_mode); // fourth = 1/4667668mpfr_t n_minus; //669mpfr_init2(n_minus, p); //670mpfr_set_ui(n_minus, n, round_mode); // n_minus = n671mpfr_sub(n_minus, n_minus, mp_one_over_24,round_mode); // n_minus = n - 1/24672673mpfr_t sqrt_n_minus; //674mpfr_init2(sqrt_n_minus, p); //675mpfr_sqrt(sqrt_n_minus, n_minus, round_mode); // n_minus = sqrt(n-1/24)676677678mpfr_sqrt_ui(mp_sqrt2, 2, round_mode); // mp_sqrt2 = sqrt(2)679mpfr_sqrt_ui(mp_sqrt3, 3, round_mode); // mp_sqrt3 = sqrt(3)680mpfr_const_pi(mp_pi, round_mode); // mp_pi = pi681682//mp_A = sqrt(2) * 3.1415926535897931 * sqrt(n - 1.0/24.0);---------------683mpfr_set(mp_A, mp_sqrt2, round_mode); // mp_A = sqrt(2)684mpfr_mul(mp_A, mp_A, mp_pi, round_mode); // mp_A = sqrt(2) * pi685mpfr_mul(mp_A, mp_A, sqrt_n_minus, round_mode); // mp_A = sqrt(2) * pi * sqrt(n - 1/24)686//------------------------------------------------------------------------687688689//mp_B = 2.0 * sqrt(3) * (n - 1.0/24.0);----------------------------------690mpfr_set_ui(mp_B, 2, round_mode); // mp_A = 2691mpfr_mul(mp_B, mp_B, mp_sqrt3, round_mode); // mp_A = 2*sqrt(3)692mpfr_mul(mp_B, mp_B, n_minus, round_mode); // mp_A = 2*sqrt(3)*(n-1/24)693//------------------------------------------------------------------------694695696//mp_C = sqrt(2) * pi * sqrt(n - 1.0/24.0) / sqrt(3);---------------------697mpfr_set(mp_C, mp_sqrt2, round_mode); // mp_C = sqrt(2)698mpfr_mul(mp_C, mp_C, mp_pi, round_mode); // mp_C = sqrt(2) * pi699mpfr_mul(mp_C, mp_C, sqrt_n_minus, round_mode); // mp_C = sqrt(2) * pi * sqrt(n - 1/24)700mpfr_div(mp_C, mp_C, mp_sqrt3, round_mode); // mp_C = sqrt(2) * pi * sqrt(n - 1/24) / sqrt3701//------------------------------------------------------------------------702703704//mp_D = 2.0 * (n - 1.0/24.0) * sqrt(n - 1.0/24.0);-----------------------705mpfr_set_ui(mp_D, 2, round_mode); // mp_D = 2706mpfr_mul(mp_D, mp_D, n_minus, round_mode); // mp_D = 2 * (n - 1/24)707mpfr_mul(mp_D, mp_D, sqrt_n_minus, round_mode); // mp_D = 2 * (n - 1/24) * sqrt(n - 1/24)708//------------------------------------------------------------------------709710mpfr_clear(n_minus);711mpfr_clear(sqrt_n_minus);712713714// some double precision versions of the above values715716d_A = sqrt(2) * d_pi * sqrt(n - 1.0/24.0);717d_B = 2.0 * sqrt(3) * (n - 1.0/24.0);718d_C = sqrt(2) * d_pi * sqrt(n - 1.0/24.0) / sqrt(3);719d_D = 2.0 * (n - 1.0/24.0) * sqrt(n - 1.0/24.0);720721ld_A = sqrtl(2) * ld_pi * sqrtl(n - 1.0L/24.0L);722ld_B = 2.0L * sqrtl(3) * (n - 1.0/24.0);723ld_C = sqrtl(2) * ld_pi * sqrtl(n - 1.0L/24.0L) / sqrtl(3);724ld_D = 2.0L * (n - 1.0L/24.0L) * sqrtl(n - 1.0L/24.0L);725726}727728void clear_constants() {729mpfr_clear(mp_one_over_12); mpfr_clear(mp_one_over_24); mpfr_clear(mp_sqrt2); mpfr_clear(mp_sqrt3); mpfr_clear(mp_pi);730mpfr_clear(mp_A); mpfr_clear(mp_B); mpfr_clear(mp_C); mpfr_clear(mp_D); mpfr_clear(half); mpfr_clear(fourth);731}732733void initialize_mpz_and_mpq_variables() {734/*735* We use a few mpz_t and mpq_t variables which need to be initialized736* before they can be used. Initialization and clearing take some737* time, so we initialize just once in this function, and clear in another.738*/739mpz_init(ztemp1);740741mpq_init(qtemps);742mpq_init(qtempa);743mpq_init(qtempa2);744}745746void clear_mpz_and_mpq_variables() {747mpz_clear(ztemp1);748749mpq_clear(qtemps);750mpq_clear(qtempa);751mpq_clear(qtempa2);752}753754void mp_f(mpfr_t result, unsigned int k) {755// compute f_n(k) as described in the introduction756//757// notice that this doesn't use n - the "constants"758// A, B, C, and D depend on n, but they are precomputed759// once before this function is called.760761//result = pi * sqrt(2) * cosh(A/(sqrt(3)*k))/(B*k) - sinh(C/k)/D;762763//764mpfr_set(result, mp_pi, round_mode); // result = pi765766mpfr_mul(result, result, mp_sqrt2, round_mode); // result = sqrt(2) * pi767//768mpfr_div(tempf1, mp_A, mp_sqrt3, round_mode); // temp1 = mp_A/sqrt(3)769mpfr_div_ui(tempf1, tempf1, k, round_mode); // temp1 = mp_A/(sqrt(3) * k)770mpfr_cosh(tempf1, tempf1, round_mode); // temp1 = cosh(mp_A/(sqrt(3) * k))771mpfr_div(tempf1, tempf1, mp_B, round_mode); // temp1 = cosh(mp_A/(sqrt(3) * k))/mp_B772mpfr_div_ui(tempf1, tempf1, k, round_mode); // temp1 = cosh(mp_A/(sqrt(3) * k))/(mp_B*k)773//774mpfr_mul(result, result, tempf1, round_mode); // result = sqrt(2) * pi * cosh(mp_A/(sqrt(3) * k))/(mp_B*k)775//776mpfr_div_ui(tempf1, mp_C, k, round_mode); // temp1 = mp_C/k777mpfr_sinh(tempf1, tempf1, round_mode); // temp1 = sinh(mp_C/k)778mpfr_div(tempf1, tempf1, mp_D, round_mode); // temp1 = sinh(mp_C/k)/D779//780mpfr_sub(result, result, tempf1, round_mode); // result = RESULT!781//782//return pi * sqrt(2) * cosh(A/(sqrt(3)*k))/(B*k) - sinh(C/k)/D;783}784785// call the following when 4k < sqrt(UINT_MAX)786//787// TODO: maybe a faster version of this can be written without using mpq_t,788// or maybe this version can be smarter.789//790// The actual value of the cosine that we compute using s(h,k)791// only depends on {s(h,k)/2}, that is, the fractional792// part of s(h,k)/2. It may be possible to make use of this somehow.793//794void q_s(mpq_t result, unsigned int h, unsigned int k) {795796if(k < 3) {797mpq_set_ui(result, 0, 1);798return;799}800801if (h == 1) {802unsigned int d = GCD( (k-1)*(k-2), 12*k);803if(d > 1) {804mpq_set_ui(result, ((k-1)*(k-2))/d, (12*k)/d);805}806else {807mpq_set_ui(result, (k-1)*(k-2), 12*k);808}809return;810}811// TODO:812// It may be advantageous to implement some of the special forms in the comments below,813// and also some more listed in some of the links mentioned in the introduction, but814// it seems like there might not be much speed benefit to this, and putting in too815// many seems to slow things down a little.816//817818// if h = 2 and k is odd, we have819// s(h,k) = (k-1)*(k-5)/24k820//if(h == 2 && k > 5 && k % 2 == 1) {821// unsigned int d = GCD( (k-1)*(k-5), 24*k);822// if(d > 1) {823// mpq_set_ui(result, ((k-1)*(k-5))/d, (24*k)/d);824// }825// else {826// mpq_set_ui(result, (k-1)*(k-5), 24*k);827// }828// return;829//}830831/*832833// if k % h == 1, then834//835// s(h,k) = (k-1)(k - h^2 - 1)/(12hk)836//837838// We need to be a little careful here because k - h^2 - 1 can be negative.839if(k % h == 1) {840int num = (k-1)*(k - h*h - 1);841int den = 12*k*h;842int d = GCD(num, den);843if(d > 1) {844mpq_set_si(result, num/d, den/d);845}846else {847mpq_set_si(result, num, den);848}849return;850}851852// if k % h == 2, then853//854// s(h,k) = (k-2)[k - .5(h^2 + 1)]/(12hk)855//856857//if(k % h == 2) {858//}859*/860861862863864mpq_set_ui(result, 0, 1); // result = 0865866int r1 = k;867int r2 = h;868869int n = 0;870int temp3;871while(r1 > 0 && r2 > 0) {872unsigned int d = GCD(r1 * r1 + r2 * r2 + 1, r1 * r2);873if(d > 1) {874mpq_set_ui(qtemps, (r1 * r1 + r2 * r2 + 1)/d, (r1 * r2)/d);875}876else{877mpq_set_ui(qtemps, r1 * r1 + r2 * r2 + 1, r1 * r2);878}879//mpq_canonicalize(qtemps);880881if(n % 2 == 0){ //882mpq_add(result, result, qtemps); // result += temp1;883} //884else { //885mpq_sub(result, result, qtemps); // result -= temp1;886} //887temp3 = r1 % r2; //888r1 = r2; //889r2 = temp3; //890n++; //891}892893mpq_set_ui(qtemps, 1, 12);894mpq_mul(result, result, qtemps); // result = result * 1.0/12.0;895896897if(n % 2 == 1) {898mpq_set_ui(qtemps, 1, 4);899mpq_sub(result, result, qtemps); // result = result - .25;900}901902}903904905void mp_a(mpfr_t result, unsigned int n, unsigned int k) {906// compute a(n,k)907908if (k == 1) {909mpfr_set_ui(result, 1, round_mode); //result = 1910return;911}912913mpfr_set_ui(result, 0, round_mode);914915unsigned int h = 0;916for(h = 1; h < k+1; h++) {917if(GCD(h,k) == 1) {918919// Note that we compute each term of the summand as920// result += cos(pi * ( s(h,k) - (2.0 * h * n)/k) );921//922// This is the real part of the exponential that was written923// down in the introduction, and we don't need to compute924// the imaginary part because we know that, in the end, the925// imaginary part will be 0, as we are computing an integer.926927q_s(qtempa, h, k);928929//mpfr_mul_q(tempa1, mp_pi, qtempa, round_mode);930//mpfr_mul_ui(tempa1, tempa1, k * k, round_mode);931932//mpfr_set_q(tempa1, qtempa, round_mode);933unsigned int r = n % k; // here we make use of the fact that the934unsigned int d = GCD(r,k); // cos() term written above only depends935unsigned int K; // on {hn/k}.936if(d > 1) {937r = r/d;938K = k/d;939}940else {941K = k;942}943if(K % 2 == 0) {944K = K/2;945}946else {947r = r * 2;948}949mpq_set_ui(qtempa2, h*r, K);950mpq_sub(qtempa, qtempa, qtempa2);951952//mpfr_set_q(tempa2, qtempa, round_mode); // This might be faster, according to953//cospi(tempa1, tempa2); // the comments in Ralf Stephan's part.c, but954// I haven't noticed a significant speed up.955// (Perhaps a different version that takes an mpq_t956// as an input might be faster.)957958mpfr_mul_q(tempa1, mp_pi, qtempa, round_mode);959mpfr_cos(tempa1, tempa1, round_mode);960mpfr_add(result, result, tempa1, round_mode);961962}963964}965966}967968template <class T>969inline T partial_sum_of_t(unsigned int n, unsigned int &k, unsigned int exit_precision, unsigned int extra_precision, double error = 0) {970unsigned int current_precision = compute_current_precision(n, k - 1, extra_precision);971T result = 0;972if(error == 0) {973for(; current_precision > exit_precision; k++) { // (don't change k -- it is already the right value)974result += sqrt(T(int(k))) * a<T>(n,k) * f<T>(k); //975current_precision = compute_current_precision(n,k,extra_precision); // The only reason that we compute the new precision976// now is so that we know when we can change to using just doubles.977// (There should be a 'long double' version of the compute_current_precision function.978}979}980else {981double remainder = 1;982for(; remainder > error; k++) { // (don't change k -- it is already the right value)983result += sqrt(T(int(k))) * a<T>(n,k) * f<T>(k); //984remainder = compute_remainder(n,k);985}986}987return result;988}989990991void mp_t(mpfr_t result, unsigned int n) {992// This is the function that actually computes p(n).993//994// More specifically, it computes t(n,N) to within 1/2 of p(n), and then995// we can find p(n) by rounding.996//997//998// NOTE: result should NOT have been initialized when this is called,999// as we initialize it to the proper precision in this function.10001001double error = .25;1002int extra = compute_extra_precision(n, error);10031004unsigned int initial_precision = compute_initial_precision(n); // We begin by computing the precision necessary to hold the final answer.1005// and then initialize both the result and some temporary variables to that1006// precision.1007mpfr_t t1, t2; //1008mpfr_init2(t1, initial_precision); //1009mpfr_init2(t2, initial_precision); //1010mpfr_init2(result, initial_precision); //1011mpfr_set_ui(result, 0, round_mode); //10121013initialize_mpz_and_mpq_variables();1014initialize_constants(initial_precision, n); // Now that we have the precision information, we initialize some constants1015// that will be used throughout, and also1016//1017initialize_mpfr_variables(initial_precision); // set the precision of the "temp" variables that are used in individual functions.10181019unsigned int current_precision = initial_precision;1020unsigned int new_precision;10211022// We start by computing with high precision arithmetic, until1023// we are sure enough that we don't need that much precision1024// anymore. Once current_precision == min_precision, we drop1025// out of this loop and switch to a computation1026// that only involves doubles.1027102810291030unsigned int k = 1; // (k holds the index of the summand that we are computing.)1031for(k = 1; current_precision > level_two_precision; k++) { //10321033mpfr_sqrt_ui(t1, k, round_mode); // t1 = sqrt(k)1034//1035mp_a(t2, n, k); // t2 = A_k(n)10361037if(debuga) {1038cout << "a(" << k << ") = ";1039mpfr_out_str(stdout, 10, 10, t2, round_mode);1040cout << endl;1041}10421043mpfr_mul(t1, t1, t2, round_mode); // t1 = sqrt(k)*A_k(n)1044//1045mp_f(t2, k); // t2 = f_k(n)10461047if(debugf) {1048cout << "f(" << n << "," << k << ") = ";1049mpfr_out_str(stdout, 10, 0, t2, round_mode);1050cout << endl;1051}10521053mpfr_mul(t1, t1, t2, round_mode); // t1 = sqrt(k)*A_k(n)*f_k(n)1054//1055mpfr_add(result, result, t1, round_mode); // result += summand10561057if(debugt) {1058int num_digits = 20;1059int num_extra_digits;1060char digits[num_digits + 1];1061num_extra_digits = grab_last_digits(digits, 5, t1);1062grab_last_digits(digits, num_digits, result);10631064mpfr_out_str(stdout, 10, 10, t1, round_mode);1065cout << endl;10661067cout << k << ": current precision:" << current_precision << ". 20 last digits of partial result: " << digits << ". Number of extra digits: " << num_extra_digits << endl;1068cout.flush();10691070}10711072new_precision = compute_current_precision(n,k,extra); // After computing one summand, check what the new precision should be.1073if(new_precision != current_precision) { // If the precision changes, we need to clear1074current_precision = new_precision; // and reinitialize all "temp" variables to1075clear_mpfr_variables(); // use lower precision.1076initialize_mpfr_variables(current_precision); //1077mpfr_clear(t1); mpfr_clear(t2); //1078mpfr_init2(t1, current_precision); //1079mpfr_init2(t2, current_precision); //1080}1081}10821083mpfr_clear(t1); mpfr_clear(t2);10841085mpfr_init2(t1, 200);1086mpfr_init2(t2, 200);10871088long double ld_partial_sum = partial_sum_of_t<long double>(n,k,level_five_precision, extra, 0);1089mpfr_set_ld(t1, ld_partial_sum, round_mode);1090mpfr_add(result, result, t1, round_mode);10911092double d_partial_sum = partial_sum_of_t<double>(n,k,0,extra,error);109310941095mpfr_set_d(t1, d_partial_sum, round_mode); //1096mpfr_add(result, result, t1, round_mode); // We add together the main result and the tail ends'109710981099mpfr_div(result, result, mp_pi, round_mode); // The actual result is the sum that we have computed1100mpfr_div(result, result, mp_sqrt2, round_mode); // divided by pi*sqrt(2).11011102clear_constants();1103clear_mpz_and_mpq_variables();1104clear_mpfr_variables();1105mpfr_clear(t1);1106mpfr_clear(t2);1107}11081109template <class T>1110T f(unsigned int k) {1111return pi_sqrt2<T>() * cosh(A<T>()/(sqrt3<T>()*k))/(B<T>() * k) - sinh(C<T>()/k)/D<T>();1112}11131114template <class T>1115T a(unsigned int n, unsigned int k) {1116if(k == 1) {1117return 1;1118}1119T result = 0;11201121unsigned int h = 0;1122for(h = 1; h < k+1; h++) {1123if(GCD(h,k) == 1) {1124result += cos( pi<T>() * ( s<T>(h,k) - T(2.0 * double(h) * n)/T(int(k))) ); // be careful to promote 2 and h to Ts1125// because the result 2 * h * n could1126// be too large.1127}1128}1129return result;1130}11311132template <class T>1133T s(unsigned int h, unsigned int k) {1134//mpq_set_ui(result, 1, 1);1135//return;11361137//return T(0); // Uncommenting this line saves 25% or more time in the computation of p(10^9) in the current version (.51)1138// but, of course, gives wrong results. (This is just to give an idea of how much time could1139// possibly be saved by optimizing this function.11401141if(k < 3) {1142return T(0);1143}11441145if (h == 1) {1146return T( int((k-1)*(k-2)) )/T(int(12 * k));1147}1148// TODO: In the function mp_s() there are a few special cases for special forms of h and k.1149// (And there are more special cases listed in one of the references listed in the introduction.)1150//1151// It may be advantageous to implement some here, but I'm not sure1152// if there is any real speed benefit to this.1153//1154// In the mpfr_t version of this function, the speedups didn't seem to help too much, but1155// they might make more of a difference here.1156//1157// Update to the above comments:1158// Actually, a few tests seem to indicate that putting in too many special1159// cases slows things down a little bit.11601161// if h = 2 and k is odd, we have1162// s(h,k) = (k-1)*(k-5)/24k1163if(h == 2 && k > 5 && k % 2 == 1) {1164return T( int((k-1)*(k-5)) )/ T(int(24*k));1165}116611671168// if k % h == 1, then1169//1170// s(h,k) = (k-1)(k - h^2 - 1)/(12hk)1171//11721173// We might need to be a little careful here because k - h^2 - 1 can be negative.1174// THIS CODE DOESN'T WORK.1175//if(k % h == 1) {1176// int num = (k-1)*(k - h*h - 1);1177// int den = 12*k*h;1178// return T(num)/T(den);1179//}11801181// if k % h == 2, then1182//1183// s(h,k) = (k-2)[k - .5(h^2 + 1)]/(12hk)1184//11851186//if(k % h == 2) {1187//}11881189int r1 = k;1190int r2 = h;11911192int n = 1;1193int temp3;11941195T result = T(0);1196T temp;1197while(r2 > 0) // Note that we maintain the invariant r1 >= r2, so1198// we only need to make sure that r2 > 01199{1200temp = T(int(r1 * r1 + r2 * r2 + 1))/(n * r1 * r2);1201temp3 = r1 % r2;1202r1 = r2;1203r2 = temp3;12041205result += temp; // result += temp1;12061207n = -n;1208}12091210result *= one_over_12<T>();12111212if(n < 0) {1213result -= T(.25);1214}1215return result;1216}121712181219long GCD(long a, long b)1220{1221long u, v, t, x;12221223if (a < 0) {1224a = -a;1225}12261227if (b < 0) {1228b = -b;1229}123012311232if (b==0)1233x = a;1234else {1235u = a;1236v = b;1237do {1238t = u % v;1239u = v;1240v = t;1241} while (v != 0);12421243x = u;1244}12451246return x;1247}1248124912501251// The following function was copied from Ralf Stephan's code,1252// mentioned in the introduction, and then some variable names1253// were changed. The function is not currently used, however.1254void cospi (mpfr_t res,1255mpfr_t x)1256{1257// mpfr_t t, tt, half, fourth;12581259// mpfr_init2 (t, prec);1260// mpfr_init2 (tt, prec);1261// mpfr_init2 (half, prec);1262// mpfr_init2 (fourth, prec);12631264// mpfr_set_ui (half, 1, r);1265// mpfr_div_2ui (half, half, 1, r);1266// mpfr_div_2ui (fourth, half, 1, r);12671268// NOTE: switched t to tempc21269// and tt to tempc1127012711272mp_rnd_t r = round_mode;127312741275mpfr_div_2ui (tempc1, x, 1, r);1276mpfr_floor (tempc1, tempc1);1277mpfr_mul_2ui (tempc1, tempc1, 1, r);1278mpfr_sub (tempc2, x, tempc1, r);1279if (mpfr_cmp_ui (tempc2, 1) > 0)1280mpfr_sub_ui (tempc2, tempc2, 2, r);1281mpfr_abs (tempc1, tempc2, r);1282if (mpfr_cmp (tempc1, half) > 0)1283{1284mpfr_ui_sub (tempc2, 1, tempc1, r);1285mpfr_abs (tempc1, tempc2, r);1286if (mpfr_cmp (tempc1, fourth) > 0)1287{1288if (mpfr_sgn (tempc2) > 0)1289mpfr_sub (tempc2, half, tempc2, r);1290else1291mpfr_add (tempc2, tempc2, half, r);1292mpfr_mul (tempc2, tempc2, mp_pi, r);1293mpfr_sin (tempc2, tempc2, r);1294}1295else1296{1297mpfr_mul (tempc2, tempc2, mp_pi, r);1298mpfr_cos (tempc2, tempc2, r);1299}1300mpfr_neg (res, tempc2, r);1301}1302else1303{1304mpfr_abs (tempc1, tempc2, r);1305if (mpfr_cmp (tempc1, fourth) > 0)1306{1307if (mpfr_sgn (tempc2) > 0)1308mpfr_sub (tempc2, half, tempc2, r);1309else1310mpfr_add (tempc2, tempc2, half, r);1311mpfr_mul (tempc2, tempc2, mp_pi, r);1312mpfr_sin (res, tempc2, r);1313}1314else1315{1316mpfr_mul (tempc2, tempc2, mp_pi, r);1317mpfr_cos (res, tempc2, r);1318}1319}13201321// mpfr_clear (half);1322// mpfr_clear (fourth);1323// mpfr_clear (t);1324// mpfr_clear (tt);1325}13261327/* answer must have already been mpz_init'd. */1328int part(mpz_t answer, unsigned int n){1329if(n == 1) {1330mpz_set_str(answer, "1", 10);1331return 0;1332}1333mpfr_t result;13341335mp_t(result, n);13361337mpfr_get_z(answer, result, round_mode);13381339mpfr_clear(result);1340return 0;1341}134213431344int main(int argc, char *argv[]){1345//init();13461347unsigned int n = 10;13481349if(argc > 1)1350if(strcmp(argv[1], "test") == 0) {1351n = test(true);1352if(n == 0) {1353cout << "All Tests Passed" << endl;1354}1355else {1356cout << "Error computing p(" << n << ")" << endl;1357}1358return 0;1359}1360else if(strcmp(argv[1], "testforever") == 0) {1361n = test(false, true);1362if(n == 0) {1363cout << "All Tests Passed" << endl;1364}1365else {1366cout << "Error computing p(" << n << ")" << endl;1367}1368return 0;1369}1370else {1371n = atoi(argv[1]);1372}1373else {1374n = test(false);1375if(n == 0) {1376cout << "All short tests passed. Run '" << argv[0] << " test' to run all tests. (This may take some time, but it gives updates as it progresses, and can be interrupted.)" << endl;1377cout << "Run with the argument 'testforever' to run tests until a failure is found (or, hopefully, to run tests forever.)" << endl;1378}1379else {1380cout << "Error computing p(" << n << ")" << endl;1381}1382return 0;1383}1384//mpfr_t result;13851386//mp_t(result, n);13871388mpz_t answer;1389mpz_init(answer);1390part(answer, n);13911392//mpfr_get_z(answer, result, round_mode);13931394mpz_out_str (stdout, 10, answer);13951396cout << endl;13971398return 0;1399}140014011402int test(bool longtest, bool forever) {1403// The exact values given below are confirmed by multiple sources, so are probably correct.1404// Other tests rely on known congruences.1405// If longtest is true, then we run some tests that probably take on the order1406// of 10 minutes.1407// If forever is true, then we just do randomized tests until a failure1408// is found. Ideally, this should mean that we test forever, of course.14091410int n;14111412mpz_t expected_value;1413mpz_t actual_value;14141415mpz_init(expected_value);1416mpz_init(actual_value);14171418n= 1;1419cout << "Computing p(" << n << ")...";1420cout.flush();1421mpz_set_str(expected_value, "1", 10);1422part(actual_value, n);14231424if(mpz_cmp(expected_value, actual_value) != 0)1425return n;14261427cout << " OK." << endl;14281429n = 10;1430cout << "Computing p(" << n << ")...";1431cout.flush();1432mpz_set_str(expected_value, "42", 10);1433part(actual_value, n);14341435if(mpz_cmp(expected_value, actual_value) != 0)1436return n;14371438cout << " OK." << endl;14391440n = 100;1441cout << "Computing p(" << n << ")...";1442cout.flush();1443mpz_set_str(expected_value, "190569292", 10);1444part(actual_value, n);14451446if(mpz_cmp(expected_value, actual_value) != 0)1447return n;14481449cout << " OK." << endl;14501451n = 1000;1452cout << "Computing p(" << n << ")...";1453cout.flush();1454mpz_set_str(expected_value, "24061467864032622473692149727991", 10);1455part(actual_value, n);14561457if(mpz_cmp(expected_value, actual_value) != 0)1458return n;14591460cout << " OK." << endl;14611462n = 10000;1463cout << "Computing p(" << n << ")...";1464cout.flush();1465mpz_set_str(expected_value, "36167251325636293988820471890953695495016030339315650422081868605887952568754066420592310556052906916435144", 10);1466part(actual_value, n);14671468if(mpz_cmp(expected_value, actual_value) != 0)1469return n;14701471cout << " OK." << endl;14721473n = 100000;1474cout << "Computing p(" << n << ")...";1475cout.flush();1476mpz_set_str(expected_value, "27493510569775696512677516320986352688173429315980054758203125984302147328114964173055050741660736621590157844774296248940493063070200461792764493033510116079342457190155718943509725312466108452006369558934464248716828789832182345009262853831404597021307130674510624419227311238999702284408609370935531629697851569569892196108480158600569421098519", 10);1477part(actual_value, n);14781479if(mpz_cmp(expected_value, actual_value) != 0)1480return n;14811482cout << " OK." << endl;14831484n = 1000000;1485cout << "Computing p(" << n << ")...";1486cout.flush();1487mpz_set_str(expected_value, "1471684986358223398631004760609895943484030484439142125334612747351666117418918618276330148873983597555842015374130600288095929387347128232270327849578001932784396072064228659048713020170971840761025676479860846908142829356706929785991290519899445490672219997823452874982974022288229850136767566294781887494687879003824699988197729200632068668735996662273816798266213482417208446631027428001918132198177180646511234542595026728424452592296781193448139994664730105742564359154794989181485285351370551399476719981691459022015599101959601417474075715430750022184895815209339012481734469448319323280150665384042994054179587751761294916248142479998802936507195257074485047571662771763903391442495113823298195263008336489826045837712202455304996382144601028531832004519046591968302787537418118486000612016852593542741980215046267245473237321845833427512524227465399130174076941280847400831542217999286071108336303316298289102444649696805395416791875480010852636774022023128467646919775022348562520747741843343657801534130704761975530375169707999287040285677841619347472368171772154046664303121315630003467104673818", 10);1488part(actual_value, n);14891490if(mpz_cmp(expected_value, actual_value) != 0)1491return n;14921493cout << " OK." << endl;149414951496// We now run some tests based on the fact that if n = 369 (mod 385) then p(n) = 0 (mod 385).14971498n = 369 + 10*385;1499cout << "Computing p(" << n << ")...";1500cout.flush();1501part(actual_value, n);1502if(mpz_divisible_ui_p(actual_value, 385) == 0)1503return n;15041505cout << " OK." << endl;15061507n = 369 + 10*385;1508cout << "Computing p(" << n << ")...";1509cout.flush();1510part(actual_value, n);1511if(mpz_divisible_ui_p(actual_value, 385) == 0)1512return n;15131514cout << " OK." << endl;15151516n = 369 + 100*385;1517cout << "Computing p(" << n << ")...";1518cout.flush();1519part(actual_value, n);1520if(mpz_divisible_ui_p(actual_value, 385) == 0)1521return n;15221523cout << " OK." << endl;15241525n = 369 + 110*385;1526cout << "Computing p(" << n << ")...";1527cout.flush();1528part(actual_value, n);1529if(mpz_divisible_ui_p(actual_value, 385) == 0)1530return n;15311532cout << " OK." << endl;15331534n = 369 + 120*385;1535cout << "Computing p(" << n << ")...";1536cout.flush();1537part(actual_value, n);1538if(mpz_divisible_ui_p(actual_value, 385) == 0)1539return n;15401541cout << " OK." << endl;15421543n = 369 + 130*385;1544cout << "Computing p(" << n << ")...";1545cout.flush();1546part(actual_value, n);1547if(mpz_divisible_ui_p(actual_value, 385) == 0)1548return n;15491550cout << " OK." << endl;15511552// Randomized testing15531554srand( time(NULL) );15551556for(int i = 0; i < 100; i++) {1557n = int(100000 * double(rand())/double(RAND_MAX) + 1);1558n = n - (n % 385) + 369;1559cout << "Computing p(" << n << ")...";1560cout.flush();1561part(actual_value, n);1562if(mpz_divisible_ui_p(actual_value, 385) == 0) {1563return n;1564}1565cout << " OK." << endl;15661567}15681569if(longtest) {1570n = 369 + 1000*385;1571cout << "Computing p(" << n << ")...";1572cout.flush();1573part(actual_value, n);1574if(mpz_divisible_ui_p(actual_value, 385) == 0)1575return n;15761577cout << " OK." << endl;15781579n = 369 + 10000*385;1580cout << "Computing p(" << n << ")...";1581cout.flush();1582part(actual_value, n);1583if(mpz_divisible_ui_p(actual_value, 385) == 0)1584return n;15851586cout << " OK." << endl;15871588n = 369 + 100000*385;1589cout << "Computing p(" << n << ")...";1590cout.flush();1591part(actual_value, n);1592if(mpz_divisible_ui_p(actual_value, 385) == 0)1593return n;15941595cout << " OK." << endl;15961597for(int i = 0; i < 20; i++) {1598n = int(100000 * double(rand())/double(RAND_MAX) + 1) + 100000;1599n = n - (n % 385) + 369;1600cout << "Computing p(" << n << ")...";1601cout.flush();1602part(actual_value, n);1603if(mpz_divisible_ui_p(actual_value, 385) == 0) {1604return n;1605}1606cout << " OK." << endl;1607}16081609for(int i = 0; i < 20; i++) {1610n = int(100000 * double(rand())/double(RAND_MAX) + 1) + 500000;1611n = n - (n % 385) + 369;1612cout << "Computing p(" << n << ")...";1613cout.flush();1614part(actual_value, n);1615if(mpz_divisible_ui_p(actual_value, 385) == 0) {1616return n;1617}1618cout << " OK." << endl;1619}16201621for(int i = 0; i < 20; i++) {1622n = int(100000 * double(rand())/double(RAND_MAX) + 1) + 1000000;1623n = n - (n % 385) + 369;1624cout << "Computing p(" << n << ")...";1625cout.flush();1626part(actual_value, n);1627if(mpz_divisible_ui_p(actual_value, 385) == 0) {1628return n;1629}1630cout << " OK." << endl;1631}16321633for(int i = 0; i < 10; i++) {1634n = int(100000 * double(rand())/double(RAND_MAX) + 1) + 10000000;1635n = n - (n % 385) + 369;1636cout << "Computing p(" << n << ")...";1637cout.flush();1638part(actual_value, n);1639if(mpz_divisible_ui_p(actual_value, 385) == 0) {1640return n;1641}1642cout << " OK." << endl;1643}16441645n = 369 + 1000000*385;1646cout << "Computing p(" << n << ")...";1647cout.flush();1648part(actual_value, n);1649if(mpz_divisible_ui_p(actual_value, 385) == 0)1650return n;16511652cout << " OK." << endl;16531654for(int i = 0; i < 10; i++) {1655n = int(100000000 * double(rand())/double(RAND_MAX) + 1) + 100000000;1656n = n - (n % 385) + 369;1657cout << "Computing p(" << n << ")...";1658cout.flush();1659part(actual_value, n);1660if(mpz_divisible_ui_p(actual_value, 385) == 0) {1661return n;1662}1663cout << " OK." << endl;1664}16651666n = 1000000000 + 139;1667cout << "Computing p(" << n << ")...";1668cout.flush();1669part(actual_value, n);1670if(mpz_divisible_ui_p(actual_value, 385) == 0)1671return n;16721673cout << " OK." << endl;167416751676for(int i = 0; i < 10; i++) {1677n = int(100000000 * double(rand())/double(RAND_MAX) + 1) + 1000000000;1678n = n - (n % 385) + 369;1679cout << "Computing p(" << n << ")...";1680cout.flush();1681part(actual_value, n);1682if(mpz_divisible_ui_p(actual_value, 385) == 0) {1683return n;1684}1685cout << " OK." << endl;1686}16871688}16891690if(forever) {1691while(1) {16921693for(int i = 0; i < 100; i++) {1694n = int(900000 * double(rand())/double(RAND_MAX) + 1) + 100000;1695n = n - (n % 385) + 369;1696cout << "Computing p(" << n << ")...";1697cout.flush();1698part(actual_value, n);1699if(mpz_divisible_ui_p(actual_value, 385) == 0) {1700return n;1701}1702cout << " OK." << endl;1703}17041705for(int i = 0; i < 50; i++) {1706n = int(9000000 * double(rand())/double(RAND_MAX) + 1) + 1000000;1707n = n - (n % 385) + 369;1708cout << "Computing p(" << n << ")...";1709cout.flush();1710part(actual_value, n);1711if(mpz_divisible_ui_p(actual_value, 385) == 0) {1712return n;1713}1714cout << " OK." << endl;1715}17161717for(int i = 0; i < 50; i++) {1718n = int(90000000 * double(rand())/double(RAND_MAX) + 1) + 10000000;1719n = n - (n % 385) + 369;1720cout << "Computing p(" << n << ")...";1721cout.flush();1722part(actual_value, n);1723if(mpz_divisible_ui_p(actual_value, 385) == 0) {1724return n;1725}1726cout << " OK." << endl;1727}17281729for(int i = 0; i < 10; i++) {1730n = int(900000000 * double(rand())/double(RAND_MAX) + 1) + 100000000;1731n = n - (n % 385) + 369;1732cout << "Computing p(" << n << ")...";1733cout.flush();1734part(actual_value, n);1735if(mpz_divisible_ui_p(actual_value, 385) == 0) {1736return n;1737}1738cout << " OK." << endl;1739}1740for(int i = 0; i < 5; i++) {1741n = int(100000000 * double(rand())/double(RAND_MAX) + 1) + 1000000000;1742n = n - (n % 385) + 369;1743cout << "Computing p(" << n << ")...";1744cout.flush();1745part(actual_value, n);1746if(mpz_divisible_ui_p(actual_value, 385) == 0) {1747return n;1748}1749cout << " OK." << endl;1750}1751}175217531754}17551756mpz_clear(expected_value);1757mpz_clear(actual_value);1758return 0;1759}17601761176217631764