/* * Calculate PI using the Borwein's Quartically Convergent Algorithm * * Init : U0 = sqrt(2) * B0 = 0 * P0 = 2 + sqrt(2) * * Iterate: * * * U = 0.5 * [ sqrt(U ) + 1 / sqrt(U ) ] * k+1 k k * * * sqrt(U ) * [ 1 + B ] * k k * B = ----------------------- * k+1 U + B * k k * * * P * B * [ 1 + U ] * k k+1 k+1 * P = ---------------------------- * k+1 1 + B * k+1 * * * P ---> PI * k+1 * */ MAPM compute_PI(int places) { MAPM t1, c0_5, u0, u1, b0, b1, p0, p1; int ct, nn, dplaces, dflag; dplaces = places + 16; // compute a few extra digits // in the intermediate math m_apm_cpp_precision(dplaces); // tell C++ about our precision dflag = FALSE; ct = 0; c0_5 = "0.5"; u0 = sqrt("2"); // make sure we use the MAPM sqrt b0 = 0; p0 = 2 + u0; while (TRUE) { /* * U = 0.5 * [ sqrt(U ) + 1 / sqrt(U ) ] * k+1 k k */ t1 = sqrt(u0); u1 = c0_5 * (t1 + 1 / t1); /* * sqrt(U ) * [ 1 + B ] * k k * B = ----------------------- * k+1 U + B * k k * */ b1 = (t1 * (1 + b0)) / (u0 + b0); /* * P * B * [ 1 + U ] * k k+1 k+1 * P = ---------------------------- * k+1 1 + B * k+1 */ p1 = (p0 * b1 * (1 + u1)) / (1 + b1); if (dflag) break; /* * compute the difference from this * iteration to the last one. */ t1 = p1 - p0; if (++ct >= 4) { /* * if diff == 0, we're done. */ if (t1 == 0) break; } /* * if the exponent of the error term (small error like 2.47...E-65) * is small enough, break out after the *next* p1 is calculated. * * get the exponent of the error term, which will be negative. */ nn = -(t1.exponent()); /* * normally, this wouldn't be here. it's nice in the demo though. */ fprintf(stderr, "PI now known to %d digits of accuracy ... \n",(2 * nn)); if ((4 * nn) >= dplaces) dflag = TRUE; /* set up for the next iteration */ /* */ /* also, keep the number of significant */ /* digits from growing without bound */ b0 = b1.round(dplaces); u0 = u1.round(dplaces); p0 = p1.round(dplaces); } /* round to the accuracy asked for */ return (p1.round(places)); }
void m_apm_cpp_precision_mt(int digits) { m_apm_enter(); m_apm_cpp_precision(digits); m_apm_leave(); }
MAPM compute_PI_2(int places) { MAPM t1, t2, c2, a0, a1, b0, b1; int kk, nn, dplaces, dflag; dplaces = places + 16; // compute a few extra digits // in the intermediate math m_apm_cpp_precision(dplaces); // tell C++ our precision requirements dflag = FALSE; kk = 0; t1 = sqrt("2.0"); // make sure we use the MAPM sqrt a0 = 6 - 4 * t1; b0 = t1 - 1; c2 = 2; while (TRUE) { t1 = b0.ipow(4); // t1 = b0 ^ 4 t1 = sqrt(sqrt(1 - t1)); // t1 = root_4(1 - t1) t1 = t1.round(dplaces); b1 = (1 - t1) / (1 + t1); b1 = b1.round(dplaces); t2 = 1 + b1; t2 = t2.ipow(4); // t2 = (1 + b1) ^ 4 t2 = t2.round(dplaces); t1 = c2.ipow(2 * kk + 3); // t1 = 2 ^ (2*kk+3) a1 = a0 * t2 - t1 * b1 * (1 + b1 + b1 * b1); a1 = a1.round(dplaces); if (dflag) break; // compute the difference from this // iteration to the last one. t1 = a1 - a0; if (kk >= 3) { // if diff == 0, we're done. if (t1 == 0) break; } /* * if the exponent of the error term (small error like 2.47...E-65) * is small enough, break out after the *next* a1 is calculated. * * get the exponent of the error term, which will be negative. */ nn = -(t1.exponent()); // normally, this wouldn't be here. it's nice in the demo though. fprintf(stderr, "PI now known to %d digits of accuracy ... \n",(4 * nn)); if ((15 * nn) >= dplaces) dflag = TRUE; // set up for the next iteration b0 = b1; a0 = a1; kk++; } // round to the accuracy asked for after taking the reciprocal t1 = 1 / a1; return(t1.round(places)); }