void eval_log(T& result, const T& arg) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types."); // // We use a variation of http://dlmf.nist.gov/4.45#i // using frexp to reduce the argument to x * 2^n, // then let y = x - 1 and compute: // log(x) = log(2) * n + log1p(1 + y) // typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type; typedef typename boost::multiprecision::detail::canonical<unsigned, 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; exp_type e; T t; eval_frexp(t, arg, &e); bool alternate = false; if(t.compare(fp_type(2) / fp_type(3)) <= 0) { alternate = true; eval_ldexp(t, t, 1); --e; } eval_multiply(result, get_constant_ln2<T>(), canonical_exp_type(e)); INSTRUMENT_BACKEND(result); eval_subtract(t, ui_type(1)); /* -0.3 <= t <= 0.3 */ if(!alternate) t.negate(); /* 0 <= t <= 0.33333 */ T pow = t; T lim; T t2; if(alternate) eval_add(result, t); else eval_subtract(result, t); eval_multiply(lim, result, std::numeric_limits<number<T, et_on> >::epsilon().backend()); if(eval_get_sign(lim) < 0) lim.negate(); INSTRUMENT_BACKEND(lim); ui_type k = 1; do { ++k; eval_multiply(pow, t); eval_divide(t2, pow, k); INSTRUMENT_BACKEND(t2); if(alternate && ((k & 1) != 0)) eval_add(result, t2); else eval_subtract(result, t2); INSTRUMENT_BACKEND(result); }while(lim.compare(t2) < 0); }
void hyp2F1(T& result, const T& a, const T& b, const T& c, const T& x) { // Compute the series representation of hyperg_2f1 taken from // Abramowitz and Stegun 15.1.1. // There are no checks on input range or parameter boundaries. typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type; T x_pow_n_div_n_fact(x); T pochham_a (a); T pochham_b (b); T pochham_c (c); T ap (a); T bp (b); T cp (c); eval_multiply(result, pochham_a, pochham_b); eval_divide(result, pochham_c); eval_multiply(result, x_pow_n_div_n_fact); eval_add(result, ui_type(1)); T lim; eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); if(eval_get_sign(lim) < 0) lim.negate(); ui_type n; T term; static const unsigned series_limit = boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; // Series expansion of hyperg_2f1(a, b; c; x). for(n = 2; n < series_limit; ++n) { eval_multiply(x_pow_n_div_n_fact, x); eval_divide(x_pow_n_div_n_fact, n); eval_increment(ap); eval_multiply(pochham_a, ap); eval_increment(bp); eval_multiply(pochham_b, bp); eval_increment(cp); eval_multiply(pochham_c, cp); eval_multiply(term, pochham_a, pochham_b); eval_divide(term, pochham_c); eval_multiply(term, x_pow_n_div_n_fact); eval_add(result, term); if(eval_get_sign(term) < 0) term.negate(); if(lim.compare(term) >= 0) break; } if(n > series_limit) BOOST_THROW_EXCEPTION(std::runtime_error("H2F1 failed to converge.")); }
void hyp0F1(T& result, const T& b, const T& x) { 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; // Compute the series representation of Hypergeometric0F1 taken from // http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F1/06/01/01/ // There are no checks on input range or parameter boundaries. T x_pow_n_div_n_fact(x); T pochham_b (b); T bp (b); eval_divide(result, x_pow_n_div_n_fact, pochham_b); eval_add(result, ui_type(1)); si_type n; T tol; tol = ui_type(1); eval_ldexp(tol, tol, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); eval_multiply(tol, result); if(eval_get_sign(tol) < 0) tol.negate(); T term; static const unsigned series_limit = boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; // Series expansion of hyperg_0f1(; b; x). for(n = 2; n < series_limit; ++n) { eval_multiply(x_pow_n_div_n_fact, x); eval_divide(x_pow_n_div_n_fact, n); eval_increment(bp); eval_multiply(pochham_b, bp); eval_divide(term, x_pow_n_div_n_fact, pochham_b); eval_add(result, term); bool neg_term = eval_get_sign(term) < 0; if(neg_term) term.negate(); if(term.compare(tol) <= 0) break; } if(n >= series_limit) BOOST_THROW_EXCEPTION(std::runtime_error("H0F1 Failed to Converge")); }
void hyp1F0(T& H1F0, const T& a, const T& x) { // Compute the series representation of Hypergeometric1F0 taken from // http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric1F0/06/01/01/ // and also see the corresponding section for the power function (i.e. x^a). // There are no checks on input range or parameter boundaries. typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type; typedef typename boost::multiprecision::detail::canonical<unsigned, 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; BOOST_ASSERT(&H1F0 != &x); BOOST_ASSERT(&H1F0 != &a); T x_pow_n_div_n_fact(x); T pochham_a (a); T ap (a); eval_multiply(H1F0, pochham_a, x_pow_n_div_n_fact); eval_add(H1F0, si_type(1)); T lim; eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); if(eval_get_sign(lim) < 0) lim.negate(); si_type n; T term, part; static const unsigned series_limit = boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; // Series expansion of hyperg_1f0(a; ; x). for(n = 2; n < series_limit; n++) { eval_multiply(x_pow_n_div_n_fact, x); eval_divide(x_pow_n_div_n_fact, n); eval_increment(ap); eval_multiply(pochham_a, ap); eval_multiply(term, pochham_a, x_pow_n_div_n_fact); eval_add(H1F0, term); if(eval_get_sign(term) < 0) term.negate(); if(lim.compare(term) >= 0) break; } if(n >= series_limit) BOOST_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge")); }
void small_sinh_series(T x, T& result) { typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type; bool neg = eval_get_sign(x) < 0; if(neg) x.negate(); T p(x); T mult(x); eval_multiply(mult, x); result = x; ui_type k = 1; T lim(x); eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value); do { eval_multiply(p, mult); eval_divide(p, ++k); eval_divide(p, ++k); eval_add(result, p); }while(p.compare(lim) >= 0); if(neg) result.negate(); }
void sinhcosh(const T& x, T* p_sinh, T* p_cosh) { typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type; typedef typename mpl::front<typename T::float_types>::type fp_type; switch(eval_fpclassify(x)) { case FP_NAN: case FP_INFINITE: if(p_sinh) *p_sinh = x; if(p_cosh) { *p_cosh = x; if(eval_get_sign(x) < 0) p_cosh->negate(); } return; case FP_ZERO: if(p_sinh) *p_sinh = x; if(p_cosh) *p_cosh = ui_type(1); return; default: ; } bool small_sinh = eval_get_sign(x) < 0 ? x.compare(fp_type(-0.5)) > 0 : x.compare(fp_type(0.5)) < 0; if(p_cosh || !small_sinh) { T e_px, e_mx; eval_exp(e_px, x); eval_divide(e_mx, ui_type(1), e_px); if(p_sinh) { if(small_sinh) { small_sinh_series(x, *p_sinh); } else { eval_subtract(*p_sinh, e_px, e_mx); eval_ldexp(*p_sinh, *p_sinh, -1); } } if(p_cosh) { eval_add(*p_cosh, e_px, e_mx); eval_ldexp(*p_cosh, *p_cosh, -1); } } else { small_sinh_series(x, *p_sinh); } }
void hyp0F0(T& H0F0, const T& x) { // Compute the series representation of Hypergeometric0F0 taken from // http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F0/06/01/ // There are no checks on input range or parameter boundaries. typedef typename mpl::front<typename T::unsigned_types>::type ui_type; BOOST_ASSERT(&H0F0 != &x); long tol = boost::multiprecision::detail::digits2<number<T, et_on> >::value; T t; T x_pow_n_div_n_fact(x); eval_add(H0F0, x_pow_n_div_n_fact, ui_type(1)); T lim; eval_ldexp(lim, H0F0, 1 - tol); if(eval_get_sign(lim) < 0) lim.negate(); ui_type n; static const unsigned series_limit = boost::multiprecision::detail::digits2<number<T, et_on> >::value < 100 ? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value; // Series expansion of hyperg_0f0(; ; x). for(n = 2; n < series_limit; ++n) { eval_multiply(x_pow_n_div_n_fact, x); eval_divide(x_pow_n_div_n_fact, n); eval_add(H0F0, x_pow_n_div_n_fact); bool neg = eval_get_sign(x_pow_n_div_n_fact) < 0; if(neg) x_pow_n_div_n_fact.negate(); if(lim.compare(x_pow_n_div_n_fact) > 0) break; if(neg) x_pow_n_div_n_fact.negate(); } if(n >= series_limit) BOOST_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge")); }
void calc_e(T& result, unsigned digits) { typedef typename mpl::front<typename T::unsigned_types>::type ui_type; // // 1100 digits in string form: // const char* string_val = "2." "7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274" "2746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101901" "1573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069" "5517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416" "9283681902551510865746377211125238978442505695369677078544996996794686445490598793163688923009879312" "7736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117" "3012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509" "9618188159304169035159888851934580727386673858942287922849989208680582574927961048419844436346324496" "8487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016" "7683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354" "0212340784981933432106817012100562788023519303322474501585390473041995777709350366041699732972508869"; // // Check if we can just construct from string: // if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits { result = string_val; return; } T lim; lim = ui_type(1); eval_ldexp(lim, lim, digits); // // Standard evaluation from the definition of e: http://functions.wolfram.com/Constants/E/02/ // result = ui_type(2); T denom; denom = ui_type(1); ui_type i = 2; do{ eval_multiply(denom, i); eval_multiply(result, i); eval_add(result, ui_type(1)); ++i; }while(denom.compare(lim) <= 0); eval_divide(result, denom); }
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::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(); }
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 eval_exp(T& result, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The exp function is only valid for floating point types."); if(&x == &result) { T temp; eval_exp(temp, x); result = temp; return; } typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type; typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type; typedef typename T::exponent_type exp_type; typedef typename boost::multiprecision::detail::canonical<exp_type, T>::type canonical_exp_type; typedef typename boost::multiprecision::detail::canonical<float, T>::type float_type; // Handle special arguments. int type = eval_fpclassify(x); bool isneg = eval_get_sign(x) < 0; if(type == FP_NAN) { result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); return; } else if(type == FP_INFINITE) { result = x; if(isneg) result = ui_type(0u); else result = x; return; } else if(type == FP_ZERO) { result = ui_type(1); return; } // Get local copy of argument and force it to be positive. T xx = x; T exp_series; if(isneg) xx.negate(); // Check the range of the argument. static const canonical_exp_type maximum_arg_for_exp = std::numeric_limits<number<T, et_on> >::max_exponent == 0 ? (std::numeric_limits<long>::max)() : std::numeric_limits<number<T, et_on> >::max_exponent; if(xx.compare(maximum_arg_for_exp) >= 0) { // Overflow / underflow if(isneg) result = ui_type(0); else result = std::numeric_limits<number<T, et_on> >::has_infinity ? std::numeric_limits<number<T, et_on> >::infinity().backend() : (std::numeric_limits<number<T, et_on> >::max)().backend(); return; } if(xx.compare(si_type(1)) <= 0) { // // Use series for exp(x) - 1: // T lim = std::numeric_limits<number<T, et_on> >::epsilon().backend(); unsigned k = 2; exp_series = xx; result = si_type(1); if(isneg) eval_subtract(result, exp_series); else eval_add(result, exp_series); eval_multiply(exp_series, xx); eval_divide(exp_series, ui_type(k)); eval_add(result, exp_series); while(exp_series.compare(lim) > 0) { ++k; eval_multiply(exp_series, xx); eval_divide(exp_series, ui_type(k)); if(isneg && (k&1)) eval_subtract(result, exp_series); else eval_add(result, exp_series); } return; } // Check for pure-integer arguments which can be either signed or unsigned. typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type ll; eval_trunc(exp_series, x); eval_convert_to(&ll, exp_series); if(x.compare(ll) == 0) { detail::pow_imp(result, get_constant_e<T>(), ll, mpl::true_()); return; } // The algorithm for exp has been taken from MPFUN. // exp(t) = [ (1 + r + r^2/2! + r^3/3! + r^4/4! ...)^p2 ] * 2^n // where p2 is a power of 2 such as 2048, r = t_prime / p2, and // t_prime = t - n*ln2, with n chosen to minimize the absolute // value of t_prime. In the resulting Taylor series, which is // implemented as a hypergeometric function, |r| is bounded by // ln2 / p2. For small arguments, no scaling is done. // Compute the exponential series of the (possibly) scaled argument. eval_divide(result, xx, get_constant_ln2<T>()); exp_type n; eval_convert_to(&n, result); // The scaling is 2^11 = 2048. static const si_type p2 = static_cast<si_type>(si_type(1) << 11); eval_multiply(exp_series, get_constant_ln2<T>(), static_cast<canonical_exp_type>(n)); eval_subtract(exp_series, xx); eval_divide(exp_series, p2); exp_series.negate(); hyp0F0(result, exp_series); detail::pow_imp(exp_series, result, p2, mpl::true_()); result = ui_type(1); eval_ldexp(result, result, n); eval_multiply(exp_series, result); if(isneg) eval_divide(result, ui_type(1), exp_series); else result = exp_series; }
void eval_atan(T& result, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan 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 mpl::front<typename T::float_types>::type fp_type; switch(eval_fpclassify(x)) { case FP_NAN: result = x; errno = EDOM; return; case FP_ZERO: result = x; return; case FP_INFINITE: if(eval_get_sign(x) < 0) { eval_ldexp(result, get_constant_pi<T>(), -1); result.negate(); } else eval_ldexp(result, get_constant_pi<T>(), -1); return; default: ; } const bool b_neg = eval_get_sign(x) < 0; T xx(x); if(b_neg) xx.negate(); if(xx.compare(fp_type(0.1)) < 0) { T t1, t2, t3; t1 = ui_type(1); t2 = fp_type(0.5f); t3 = fp_type(1.5f); eval_multiply(xx, xx); xx.negate(); hyp2F1(result, t1, t2, t3, xx); eval_multiply(result, x); return; } if(xx.compare(fp_type(10)) > 0) { T t1, t2, t3; t1 = fp_type(0.5f); t2 = ui_type(1u); t3 = fp_type(1.5f); eval_multiply(xx, xx); eval_divide(xx, si_type(-1), xx); hyp2F1(result, t1, t2, t3, xx); eval_divide(result, x); if(!b_neg) result.negate(); eval_ldexp(t1, get_constant_pi<T>(), -1); eval_add(result, t1); if(b_neg) result.negate(); return; } // Get initial estimate using standard math function atan. fp_type d; eval_convert_to(&d, xx); result = fp_type(std::atan(d)); // 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; T s, c, t; while(current_precision > target_precision) { eval_sin(s, result); eval_cos(c, result); eval_multiply(t, xx, c); eval_subtract(t, s); eval_multiply(s, t, c); eval_add(result, s); current_precision = eval_ilogb(s); if(current_precision <= (std::numeric_limits<typename T::exponent_type>::min)() + 1) break; } if(b_neg) result.negate(); }
void eval_atan2(T& result, const T& y, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan2 function is only valid for floating point types."); if(&result == &y) { T temp(y); eval_atan2(result, temp, x); return; } else if(&result == &x) { T temp(x); eval_atan2(result, y, temp); return; } typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type; switch(eval_fpclassify(y)) { case FP_NAN: result = y; errno = EDOM; return; case FP_ZERO: { if(eval_signbit(x)) { result = get_constant_pi<T>(); if(eval_signbit(y)) result.negate(); } else { result = y; // Note we allow atan2(0,0) to be +-zero, even though it's mathematically undefined } return; } case FP_INFINITE: { if(eval_fpclassify(x) == FP_INFINITE) { if(eval_signbit(x)) { // 3Pi/4 eval_ldexp(result, get_constant_pi<T>(), -2); eval_subtract(result, get_constant_pi<T>()); if(eval_get_sign(y) >= 0) result.negate(); } else { // Pi/4 eval_ldexp(result, get_constant_pi<T>(), -2); if(eval_get_sign(y) < 0) result.negate(); } } else { eval_ldexp(result, get_constant_pi<T>(), -1); if(eval_get_sign(y) < 0) result.negate(); } return; } } switch(eval_fpclassify(x)) { case FP_NAN: result = x; errno = EDOM; return; case FP_ZERO: { eval_ldexp(result, get_constant_pi<T>(), -1); if(eval_get_sign(y) < 0) result.negate(); return; } case FP_INFINITE: if(eval_get_sign(x) > 0) result = ui_type(0); else result = get_constant_pi<T>(); if(eval_get_sign(y) < 0) result.negate(); return; } T xx; eval_divide(xx, y, x); if(eval_get_sign(xx) < 0) xx.negate(); eval_atan(result, xx); // Determine quadrant (sign) based on signs of x, y const bool y_neg = eval_get_sign(y) < 0; const bool x_neg = eval_get_sign(x) < 0; if(y_neg != x_neg) result.negate(); if(x_neg) { if(y_neg) eval_subtract(result, get_constant_pi<T>()); else eval_add(result, get_constant_pi<T>()); } }
ast_t* eval_expression(env_t* env, ast_t* ast) { switch(ast->type) { /* valid */ case at_call: return eval_call(env,ast); case at_identifier: return get_ast_by_id(env, ast->data.id); case at_expression: { ast_t* result = NULL; ast_t* left = eval_expression(env, ast->data.expression.left); ast_t* right = eval_expression(env, ast->data.expression.right); inc_ref(left); inc_ref(right); switch(ast->data.expression.op) { case op_add: result = eval_add(env, left, right); break; case op_mul: result = eval_mul(env, left, right); break; case op_div: result = eval_div(env, left, right); break; case op_sub: result = eval_sub(env, left, right); break; case op_mod: result = eval_mod(env, left, right); break; case op_and: result = eval_and(env, left, right); break; case op_or: result = eval_or(env, left, right); break; case op_gt: result = eval_gt(env, left, right); break; case op_ge: result = eval_ge(env, left, right); break; case op_lt: result = eval_lt(env, left, right); break; case op_le: result = eval_le(env, left, right); break; case op_eq: result = eval_eq(env, left, right); break; case op_neq: result = eval_neq(env, left, right); break; case op_cat: result = eval_cat(env, left, right); break; case op_deref: { ast_t* index = eval_expression(env, right); if (index->type != at_integer) { // TODO: error -> index must be an integer! } else { switch(left->type) { case at_list: result = left->data.list.elements[index->data.i]; } } } } result->ref_count = 0; dec_ref(left); dec_ref(right); return result; } /* no need to evaluate */ case at_integer: case at_bool: case at_double: case at_string: case at_function: case at_statements: case at_list: return ast; /* invalid */ case at_assignment: case at_callargs: case at_conditional: case at_dowhile: case at_elif: case at_if: case at_params: case at_while: case at_builtin: error_expected(NULL,"expression",get_ast_type_name(ast->type)); } return NULL; /* this should never happen */ }
Value * visit(Add const * e) { return eval_add(e->left->accept(*this), e->right->accept(*this)); }
void eval_atan2(T& result, const T& y, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan2 function is only valid for floating point types."); if(&result == &y) { T temp(y); eval_atan2(result, temp, x); return; } else if(&result == &x) { T temp(x); eval_atan2(result, y, temp); return; } typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type; switch(eval_fpclassify(y)) { case FP_NAN: result = y; return; case FP_ZERO: { int c = eval_get_sign(x); if(c < 0) result = get_constant_pi<T>(); else if(c >= 0) result = ui_type(0); // Note we allow atan2(0,0) to be zero, even though it's mathematically undefined return; } case FP_INFINITE: { if(eval_fpclassify(x) == 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.")); } else { eval_ldexp(result, get_constant_pi<T>(), -1); if(eval_get_sign(y) < 0) result.negate(); } return; } } switch(eval_fpclassify(x)) { case FP_NAN: result = x; return; case FP_ZERO: { eval_ldexp(result, get_constant_pi<T>(), -1); if(eval_get_sign(y) < 0) result.negate(); return; } case FP_INFINITE: if(eval_get_sign(x) > 0) result = ui_type(0); else result = get_constant_pi<T>(); if(eval_get_sign(y) < 0) result.negate(); return; } T xx; eval_divide(xx, y, x); if(eval_get_sign(xx) < 0) xx.negate(); eval_atan(result, xx); // Determine quadrant (sign) based on signs of x, y const bool y_neg = eval_get_sign(y) < 0; const bool x_neg = eval_get_sign(x) < 0; if(y_neg != x_neg) result.negate(); if(x_neg) { if(y_neg) eval_subtract(result, get_constant_pi<T>()); else eval_add(result, get_constant_pi<T>()); } }
void eval_atan(T& result, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan 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 mpl::front<typename T::float_types>::type fp_type; switch(eval_fpclassify(x)) { case FP_NAN: result = x; return; case FP_ZERO: result = ui_type(0); return; case FP_INFINITE: if(eval_get_sign(x) < 0) { eval_ldexp(result, get_constant_pi<T>(), -1); result.negate(); } else eval_ldexp(result, get_constant_pi<T>(), -1); return; default: ; } const bool b_neg = eval_get_sign(x) < 0; T xx(x); if(b_neg) xx.negate(); if(xx.compare(fp_type(0.1)) < 0) { T t1, t2, t3; t1 = ui_type(1); t2 = fp_type(0.5f); t3 = fp_type(1.5f); eval_multiply(xx, xx); xx.negate(); hyp2F1(result, t1, t2, t3, xx); eval_multiply(result, x); return; } if(xx.compare(fp_type(10)) > 0) { T t1, t2, t3; t1 = fp_type(0.5f); t2 = ui_type(1u); t3 = fp_type(1.5f); eval_multiply(xx, xx); eval_divide(xx, si_type(-1), xx); hyp2F1(result, t1, t2, t3, xx); eval_divide(result, x); if(!b_neg) result.negate(); eval_ldexp(t1, get_constant_pi<T>(), -1); eval_add(result, t1); if(b_neg) result.negate(); return; } // Get initial estimate using standard math function atan. fp_type d; eval_convert_to(&d, xx); result = fp_type(std::atan(d)); // Newton-Raphson iteration static const boost::int32_t double_digits10_minus_a_few = std::numeric_limits<double>::digits10 - 3; T s, c, t; for(boost::int32_t digits = double_digits10_minus_a_few; digits <= std::numeric_limits<number<T, et_on> >::digits10; digits *= 2) { eval_sin(s, result); eval_cos(c, result); eval_multiply(t, xx, c); eval_subtract(t, s); eval_multiply(s, t, c); eval_add(result, s); } if(b_neg) result.negate(); }
void eval_cos(T& result, const T& x) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The cos function is only valid for floating point types."); if(&result == &x) { T temp; eval_cos(temp, x); result = temp; return; } 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; switch(eval_fpclassify(x)) { case FP_INFINITE: case FP_NAN: result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); return; case FP_ZERO: result = ui_type(1); return; default: ; } // Local copy of the argument T xx = x; // Analyze and prepare the phase of the argument. // Make a local, positive copy of the argument, xx. // The argument xx will be reduced to 0 <= xx <= pi/2. bool b_negate_cos = false; if(eval_get_sign(x) < 0) { xx.negate(); } T n_pi, t; // Remove even multiples of pi. if(xx.compare(get_constant_pi<T>()) > 0) { eval_divide(t, xx, get_constant_pi<T>()); eval_trunc(n_pi, t); BOOST_MATH_INSTRUMENT_CODE(n_pi.str(0, std::ios_base::scientific)); eval_multiply(t, n_pi, get_constant_pi<T>()); BOOST_MATH_INSTRUMENT_CODE(t.str(0, std::ios_base::scientific)); eval_subtract(xx, t); BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific)); // Adjust signs if the multiple of pi is not even. t = ui_type(2); eval_fmod(t, n_pi, t); const bool b_n_pi_is_even = eval_get_sign(t) == 0; if(!b_n_pi_is_even) { b_negate_cos = !b_negate_cos; } } // Reduce the argument to 0 <= xx <= pi/2. eval_ldexp(t, get_constant_pi<T>(), -1); int com = xx.compare(t); if(com > 0) { eval_subtract(xx, get_constant_pi<T>(), xx); b_negate_cos = !b_negate_cos; BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific)); } const bool b_zero = eval_get_sign(xx) == 0; const bool b_pi_half = com == 0; // Check if the reduced argument is very close to 0 or pi/2. const bool b_near_zero = xx.compare(fp_type(1e-4)) < 0; eval_subtract(t, xx); const bool b_near_pi_half = t.compare(fp_type(1e-4)) < 0; if(b_zero) { result = si_type(1); } else if(b_pi_half) { result = si_type(0); } else if(b_near_zero) { eval_multiply(t, xx, xx); eval_divide(t, si_type(-4)); n_pi = fp_type(0.5f); hyp0F1(result, n_pi, t); BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific)); } else if(b_near_pi_half) { T t2(t); eval_multiply(t, t); eval_divide(t, si_type(-4)); n_pi = fp_type(1.5f); hyp0F1(result, n_pi, t); eval_multiply(result, t2); BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific)); } else { // Scale to a small argument for an efficient Taylor series, // implemented as a hypergeometric function. Use a standard // divide by three identity a certain number of times. // Here we use division by 3^9 --> (19683 = 3^9). static const ui_type n_scale = 9; static const ui_type n_three_pow_scale = 19683; eval_divide(xx, n_three_pow_scale); eval_multiply(t, xx, xx); eval_divide(t, si_type(-4)); n_pi = fp_type(0.5f); // Now with small arguments, we are ready for a series expansion. hyp0F1(result, n_pi, t); BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific)); // Convert back using multiple angle identity. for(ui_type k = 0; k < n_scale; k++) { eval_multiply(t, result, result); eval_multiply(t, result); eval_multiply(t, ui_type(4)); eval_multiply(result, si_type(-3)); eval_add(result, t); } } if(b_negate_cos) 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 calc_log2(T& num, unsigned digits) { typedef typename geofeatures_boost::multiprecision::detail::canonical<geofeatures_boost::uint32_t, T>::type ui_type; typedef typename mpl::front<typename T::signed_types>::type si_type; // // String value with 1100 digits: // static const char* string_val = "0." "6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875" "4200148102057068573368552023575813055703267075163507596193072757082837143519030703862389167347112335" "0115364497955239120475172681574932065155524734139525882950453007095326366642654104239157814952043740" "4303855008019441706416715186447128399681717845469570262716310645461502572074024816377733896385506952" "6066834113727387372292895649354702576265209885969320196505855476470330679365443254763274495125040606" "9438147104689946506220167720424524529612687946546193165174681392672504103802546259656869144192871608" "2938031727143677826548775664850856740776484514644399404614226031930967354025744460703080960850474866" "3852313818167675143866747664789088143714198549423151997354880375165861275352916610007105355824987941" "4729509293113897155998205654392871700072180857610252368892132449713893203784393530887748259701715591" "0708823683627589842589185353024363421436706118923678919237231467232172053401649256872747782344535347" "6481149418642386776774406069562657379600867076257199184734022651462837904883062033061144630073719489"; // // Check if we can just construct from string: // if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits { num = string_val; return; } // // We calculate log2 from using the formula: // // ln(2) = 3/4 SUM[n>=0] ((-1)^n * N!^2 / (2^n(2n+1)!)) // // Numerator and denominator are calculated separately and then // divided at the end, we also precalculate the terms up to n = 5 // since these fit in a 32-bit integer anyway. // // See Gourdon, X., and Sebah, P. The logarithmic constant: log 2, Jan. 2004. // Also http://www.mpfr.org/algorithms.pdf. // num = static_cast<ui_type>(1180509120uL); T denom, next_term, temp; denom = static_cast<ui_type>(1277337600uL); next_term = static_cast<ui_type>(120uL); si_type sign = -1; ui_type limit = digits / 3 + 1; for(ui_type n = 6; n < limit; ++n) { temp = static_cast<ui_type>(2); eval_multiply(temp, ui_type(2 * n)); eval_multiply(temp, ui_type(2 * n + 1)); eval_multiply(num, temp); eval_multiply(denom, temp); sign = -sign; eval_multiply(next_term, n); eval_multiply(temp, next_term, next_term); if(sign < 0) temp.negate(); eval_add(num, temp); } eval_multiply(denom, ui_type(4)); eval_multiply(num, ui_type(3)); INSTRUMENT_BACKEND(denom); INSTRUMENT_BACKEND(num); eval_divide(num, denom); INSTRUMENT_BACKEND(num); }