void eval_asin(T& result, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The asin function is only valid for floating point types."); typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type; typedef typename mpl::front<typename T::float_types>::type fp_type; if(&result == &x) { T t(x); eval_asin(result, t); return; } switch(eval_fpclassify(x)) { case FP_NAN: case FP_INFINITE: if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN) result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); else BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type.")); return; case FP_ZERO: result = ui_type(0); return; default: ; } const bool b_neg = eval_get_sign(x) < 0; T xx(x); if(b_neg) xx.negate(); int c = xx.compare(ui_type(1)); if(c > 0) { if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN) result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); else BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type.")); return; } else if(c == 0) { result = get_constant_pi<T>(); eval_ldexp(result, result, -1); if(b_neg) result.negate(); return; } if(xx.compare(fp_type(1e-4)) < 0) { // http://functions.wolfram.com/ElementaryFunctions/ArcSin/26/01/01/ eval_multiply(xx, xx); T t1, t2; t1 = fp_type(0.5f); t2 = fp_type(1.5f); hyp2F1(result, t1, t1, t2, xx); eval_multiply(result, x); return; } else if(xx.compare(fp_type(1 - 1e-4f)) > 0) { T dx1; T t1, t2; eval_subtract(dx1, ui_type(1), xx); t1 = fp_type(0.5f); t2 = fp_type(1.5f); eval_ldexp(dx1, dx1, -1); hyp2F1(result, t1, t1, t2, dx1); eval_ldexp(dx1, dx1, 2); eval_sqrt(t1, dx1); eval_multiply(result, t1); eval_ldexp(t1, get_constant_pi<T>(), -1); result.negate(); eval_add(result, t1); if(b_neg) result.negate(); return; } #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS typedef typename boost::multiprecision::detail::canonical<long double, T>::type guess_type; #else typedef fp_type guess_type; #endif // Get initial estimate using standard math function asin. guess_type dd; eval_convert_to(&dd, xx); result = (guess_type)(std::asin(dd)); unsigned current_digits = std::numeric_limits<guess_type>::digits - 5; unsigned target_precision = boost::multiprecision::detail::digits2<number<T, et_on> >::value; // Newton-Raphson iteration while(current_digits < target_precision) { T sine, cosine; eval_sin(sine, result); eval_cos(cosine, result); eval_subtract(sine, xx); eval_divide(sine, cosine); eval_subtract(result, sine); current_digits *= 2; /* T lim; eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); if(eval_get_sign(s) < 0) s.negate(); if(eval_get_sign(lim) < 0) lim.negate(); if(lim.compare(s) >= 0) break; */ } if(b_neg) result.negate(); }
void eval_asin(T& result, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The asin function is only valid for floating point types."); typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type; typedef typename mpl::front<typename T::float_types>::type fp_type; if(&result == &x) { T t(x); eval_asin(result, t); return; } switch(eval_fpclassify(x)) { case FP_NAN: case FP_INFINITE: if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN) { result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); errno = EDOM; } else BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type.")); return; case FP_ZERO: result = x; return; default: ; } const bool b_neg = eval_get_sign(x) < 0; T xx(x); if(b_neg) xx.negate(); int c = xx.compare(ui_type(1)); if(c > 0) { if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN) { result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); errno = EDOM; } else BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type.")); return; } else if(c == 0) { result = get_constant_pi<T>(); eval_ldexp(result, result, -1); if(b_neg) result.negate(); return; } if(xx.compare(fp_type(1e-4)) < 0) { // http://functions.wolfram.com/ElementaryFunctions/ArcSin/26/01/01/ eval_multiply(xx, xx); T t1, t2; t1 = fp_type(0.5f); t2 = fp_type(1.5f); hyp2F1(result, t1, t1, t2, xx); eval_multiply(result, x); return; } else if(xx.compare(fp_type(1 - 1e-4f)) > 0) { T dx1; T t1, t2; eval_subtract(dx1, ui_type(1), xx); t1 = fp_type(0.5f); t2 = fp_type(1.5f); eval_ldexp(dx1, dx1, -1); hyp2F1(result, t1, t1, t2, dx1); eval_ldexp(dx1, dx1, 2); eval_sqrt(t1, dx1); eval_multiply(result, t1); eval_ldexp(t1, get_constant_pi<T>(), -1); result.negate(); eval_add(result, t1); if(b_neg) result.negate(); return; } #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS typedef typename boost::multiprecision::detail::canonical<long double, T>::type guess_type; #else typedef fp_type guess_type; #endif // Get initial estimate using standard math function asin. guess_type dd; eval_convert_to(&dd, xx); result = (guess_type)(std::asin(dd)); // Newton-Raphson iteration, we should double our precision with each iteration, // in practice this seems to not quite work in all cases... so terminate when we // have at least 2/3 of the digits correct on the assumption that the correction // we've just added will finish the job... boost::intmax_t current_precision = eval_ilogb(result); boost::intmax_t target_precision = current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3; // Newton-Raphson iteration while(current_precision > target_precision) { T sine, cosine; eval_sin(sine, result); eval_cos(cosine, result); eval_subtract(sine, xx); eval_divide(sine, cosine); eval_subtract(result, sine); current_precision = eval_ilogb(sine); if(current_precision <= (std::numeric_limits<typename T::exponent_type>::min)() + 1) break; } if(b_neg) result.negate(); }
void calc_pi(T& result, unsigned digits) { typedef typename mpl::front<typename T::unsigned_types>::type ui_type; typedef typename mpl::front<typename T::float_types>::type real_type; // // 1100 digits in string form: // const char* string_val = "3." "1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679" "8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196" "4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273" "7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094" "3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912" "9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132" "0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235" "4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859" "5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303" "5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989" "3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913152"; // // Check if we can just construct from string: // if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits { result = string_val; return; } T a; a = ui_type(1); T b; T A(a); T B; B = real_type(0.5f); T D; D = real_type(0.25f); T lim; lim = ui_type(1); eval_ldexp(lim, lim, -(int)digits); // // This algorithm is from: // Schonhage, A., Grotefeld, A. F. W., and Vetter, E. Fast Algorithms: A Multitape Turing // Machine Implementation. BI Wissenschaftverlag, 1994. // Also described in MPFR's algorithm guide: http://www.mpfr.org/algorithms.pdf. // // Let: // a[0] = A[0] = 1 // B[0] = 1/2 // D[0] = 1/4 // Then: // S[k+1] = (A[k]+B[k]) / 4 // b[k] = sqrt(B[k]) // a[k+1] = a[k]^2 // B[k+1] = 2(A[k+1]-S[k+1]) // D[k+1] = D[k] - 2^k(A[k+1]-B[k+1]) // Stop when |A[k]-B[k]| <= 2^(k-p) // and PI = B[k]/D[k] unsigned k = 1; do { eval_add(result, A, B); eval_ldexp(result, result, -2); eval_sqrt(b, B); eval_add(a, b); eval_ldexp(a, a, -1); eval_multiply(A, a, a); eval_subtract(B, A, result); eval_ldexp(B, B, 1); eval_subtract(result, A, B); bool neg = eval_get_sign(result) < 0; if(neg) result.negate(); if(result.compare(lim) <= 0) break; if(neg) result.negate(); eval_ldexp(result, result, k - 1); eval_subtract(D, result); ++k; eval_ldexp(lim, lim, 1); } while(true); eval_divide(result, B, D); }
void eval_asin(T& result, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The asin function is only valid for floating point types."); typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type; typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type; typedef typename T::exponent_type exp_type; typedef typename boost::multiprecision::detail::canonical<exp_type, T>::type canonical_exp_type; typedef typename mpl::front<typename T::float_types>::type fp_type; if(&result == &x) { T t(x); eval_asin(result, t); return; } switch(eval_fpclassify(x)) { case FP_NAN: case FP_INFINITE: result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); return; case FP_ZERO: result = ui_type(0); return; default: ; } const bool b_neg = eval_get_sign(x) < 0; T xx(x); if(b_neg) xx.negate(); int c = xx.compare(ui_type(1)); if(c > 0) { result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); return; } else if(c == 0) { result = get_constant_pi<T>(); eval_ldexp(result, result, -1); if(b_neg) result.negate(); return; } if(xx.compare(fp_type(1e-4)) < 0) { // http://functions.wolfram.com/ElementaryFunctions/ArcSin/26/01/01/ eval_multiply(xx, xx); T t1, t2; t1 = fp_type(0.5f); t2 = fp_type(1.5f); hyp2F1(result, t1, t1, t2, xx); eval_multiply(result, x); return; } else if(xx.compare(fp_type(1 - 1e-4f)) > 0) { T dx1; T t1, t2; eval_subtract(dx1, ui_type(1), xx); t1 = fp_type(0.5f); t2 = fp_type(1.5f); eval_ldexp(dx1, dx1, -1); hyp2F1(result, t1, t1, t2, dx1); eval_ldexp(dx1, dx1, 2); eval_sqrt(t1, dx1); eval_multiply(result, t1); eval_ldexp(t1, get_constant_pi<T>(), -1); result.negate(); eval_add(result, t1); if(b_neg) result.negate(); return; } // Get initial estimate using standard math function asin. double dd; eval_convert_to(&dd, xx); result = fp_type(std::asin(dd)); // Newton-Raphson iteration while(true) { T s, c; eval_sin(s, result); eval_cos(c, result); eval_subtract(s, xx); eval_divide(s, c); eval_subtract(result, s); T lim; eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); if(eval_get_sign(s) < 0) s.negate(); if(eval_get_sign(lim) < 0) lim.negate(); if(lim.compare(s) >= 0) break; } if(b_neg) result.negate(); }