inline T asymptotic_bessel_j_large_x_2(T v, T x) { // See A&S 9.2.19. BOOST_MATH_STD_USING // Get the phase and amplitude: T ampl = asymptotic_bessel_amplitude(v, x); T phase = asymptotic_bessel_phase_mx(v, x); BOOST_MATH_INSTRUMENT_VARIABLE(ampl); BOOST_MATH_INSTRUMENT_VARIABLE(phase); // // Calculate the sine of the phase, using // sine/cosine addition rules to factor in // the x - PI(v/2 + 1/4) term not added to the // phase when we calculated it. // BOOST_MATH_INSTRUMENT_CODE(cos(phase)); BOOST_MATH_INSTRUMENT_CODE(cos(x)); BOOST_MATH_INSTRUMENT_CODE(sin(phase)); BOOST_MATH_INSTRUMENT_CODE(sin(x)); T cx = cos(x); T sx = sin(x); T ci = cos_pi(v / 2 + 0.25f); T si = sin_pi(v / 2 + 0.25f); T sin_phase = cos(phase) * (cx * ci + sx * si) - sin(phase) * (sx * ci - cx * si); BOOST_MATH_INSTRUMENT_VARIABLE(sin_phase); return sin_phase * ampl; }
int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag) { typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits; BOOST_MATH_INSTRUMENT_VARIABLE(x); BOOST_DEDUCED_TYPENAME traits::bits a; traits::get_bits(x,a); BOOST_MATH_INSTRUMENT_VARIABLE(a); a &= traits::exponent | traits::flag | traits::significand; BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand)); BOOST_MATH_INSTRUMENT_VARIABLE(a); if(a <= traits::significand) { if(a == 0) return FP_ZERO; else return FP_SUBNORMAL; } if(a < traits::exponent) return FP_NORMAL; a &= traits::significand; if(a == 0) return FP_INFINITE; return FP_NAN; }
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&) { BOOST_MATH_INSTRUMENT_VARIABLE(t); // whenever possible check for Nan's first: #if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) if(::mars_boost::math_detail::is_nan_helper(t, ::mars_boost::is_floating_point<T>())) return FP_NAN; #elif defined(isnan) if(mars_boost::math_detail::is_nan_helper(t, ::mars_boost::is_floating_point<T>())) return FP_NAN; #elif defined(_MSC_VER) || defined(__BORLANDC__) if(::_isnan(mars_boost::math::tools::real_cast<double>(t))) return FP_NAN; #endif // std::fabs broken on a few systems especially for long long!!!! T at = (t < T(0)) ? -t : t; // Use a process of exclusion to figure out // what kind of type we have, this relies on // IEEE conforming reals that will treat // Nan's as unordered. Some compilers // don't do this once optimisations are // turned on, hence the check for nan's above. if(at <= (std::numeric_limits<T>::max)()) { if(at >= (std::numeric_limits<T>::min)()) return FP_NORMAL; return (at != 0) ? FP_SUBNORMAL : FP_ZERO; } else if(at > (std::numeric_limits<T>::max)()) return FP_INFINITE; return FP_NAN; }
inline unsigned round_x_from_q(unsigned x, T q, T cum, T fudge_factor, unsigned /*lbound*/, unsigned ubound, const policies::discrete_quantile<policies::integer_round_up>&) { if((q < cum * fudge_factor) && (x != ubound)) { BOOST_MATH_INSTRUMENT_VARIABLE(x+1); return ++x; } return x; }
inline unsigned round_x_from_q(unsigned x, T q, T cum, T fudge_factor, unsigned lbound, unsigned /*ubound*/, const policies::discrete_quantile<policies::integer_round_down>&) { if((q * fudge_factor > cum) && (x != lbound)) { BOOST_MATH_INSTRUMENT_VARIABLE(x-1); return --x; } return x; }
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&) { #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS if(std::numeric_limits<T>::is_specialized) return fpclassify_imp(t, generic_tag<true>()); #endif // // An unknown type with no numeric_limits support, // so what are we supposed to do we do here? // BOOST_MATH_INSTRUMENT_VARIABLE(t); return t == 0 ? FP_ZERO : FP_NORMAL; }
T hypergeometric_cdf_imp(unsigned x, unsigned r, unsigned n, unsigned N, bool invert, const Policy& pol) { #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable:4267) #endif BOOST_MATH_STD_USING T result = 0; T mode = floor(T(r + 1) * T(n + 1) / (N + 2)); if(x < mode) { result = hypergeometric_pdf<T>(x, r, n, N, pol); T diff = result; unsigned lower_limit = static_cast<unsigned>((std::max)(0, (int)(n + r) - (int)(N))); while(diff > (invert ? T(1) : result) * tools::epsilon<T>()) { diff = T(x) * T((N + x) - n - r) * diff / (T(1 + n - x) * T(1 + r - x)); result += diff; BOOST_MATH_INSTRUMENT_VARIABLE(x); BOOST_MATH_INSTRUMENT_VARIABLE(diff); BOOST_MATH_INSTRUMENT_VARIABLE(result); if(x == lower_limit) break; --x; } } else { invert = !invert; unsigned upper_limit = (std::min)(r, n); if(x != upper_limit) { ++x; result = hypergeometric_pdf<T>(x, r, n, N, pol); T diff = result; while((x <= upper_limit) && (diff > (invert ? T(1) : result) * tools::epsilon<T>())) { diff = T(n - x) * T(r - x) * diff / (T(x + 1) * T((N + x + 1) - n - r)); result += diff; ++x; BOOST_MATH_INSTRUMENT_VARIABLE(x); BOOST_MATH_INSTRUMENT_VARIABLE(diff); BOOST_MATH_INSTRUMENT_VARIABLE(result); } } } if(invert) result = 1 - result; return result; #ifdef BOOST_MSVC # pragma warning(pop) #endif }
T halley_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) { BOOST_MATH_STD_USING T f0(0), f1, f2; T result = guess; T factor = static_cast<T>(ldexp(1.0, 1 - digits)); T delta = (std::max)(T(10000000 * guess), T(10000000)); // arbitarily large delta T last_f0 = 0; T delta1 = delta; T delta2 = delta; bool out_of_bounds_sentry = false; #ifdef BOOST_MATH_INSTRUMENT std::cout << "Halley iteration, limit = " << factor << std::endl; #endif boost::uintmax_t count(max_iter); do{ last_f0 = f0; delta2 = delta1; delta1 = delta; boost::math::tie(f0, f1, f2) = f(result); BOOST_MATH_INSTRUMENT_VARIABLE(f0); BOOST_MATH_INSTRUMENT_VARIABLE(f1); BOOST_MATH_INSTRUMENT_VARIABLE(f2); if(0 == f0) break; if((f1 == 0) && (f2 == 0)) { // Oops zero derivative!!! #ifdef BOOST_MATH_INSTRUMENT std::cout << "Halley iteration, zero derivative found" << std::endl; #endif detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max); } else { if(f2 != 0) { T denom = 2 * f0; T num = 2 * f1 - f0 * (f2 / f1); BOOST_MATH_INSTRUMENT_VARIABLE(denom); BOOST_MATH_INSTRUMENT_VARIABLE(num); if((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value<T>())) { // possible overflow, use Newton step: delta = f0 / f1; } else delta = denom / num; if(delta * f1 / f0 < 0) { // probably cancellation error, try a Newton step instead: delta = f0 / f1; } } else delta = f0 / f1; } #ifdef BOOST_MATH_INSTRUMENT std::cout << "Halley iteration, delta = " << delta << std::endl; #endif T convergence = fabs(delta / delta2); if((convergence > 0.8) && (convergence < 2)) { // last two steps haven't converged, try bisection: delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2; if(fabs(delta) > result) delta = sign(delta) * result; // protect against huge jumps! // reset delta2 so that this branch will *not* be taken on the // next iteration: delta2 = delta * 3; BOOST_MATH_INSTRUMENT_VARIABLE(delta); } guess = result; result -= delta; BOOST_MATH_INSTRUMENT_VARIABLE(result); // check for out of bounds step: if(result < min) { T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min))) ? T(1000) : T(result / min); if(fabs(diff) < 1) diff = 1 / diff; if(!out_of_bounds_sentry && (diff > 0) && (diff < 3)) { // Only a small out of bounds step, lets assume that the result // is probably approximately at min: delta = 0.99f * (guess - min); result = guess - delta; out_of_bounds_sentry = true; // only take this branch once! } else { delta = (guess - min) / 2; result = guess - delta; if((result == min) || (result == max)) break; } } else if(result > max) { T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(max))) ? T(1000) : T(result / max); if(fabs(diff) < 1) diff = 1 / diff; if(!out_of_bounds_sentry && (diff > 0) && (diff < 3)) { // Only a small out of bounds step, lets assume that the result // is probably approximately at min: delta = 0.99f * (guess - max); result = guess - delta; out_of_bounds_sentry = true; // only take this branch once! } else { delta = (guess - max) / 2; result = guess - delta; if((result == min) || (result == max)) break; } } // update brackets: if(delta > 0) max = guess; else min = guess; }while(--count && (fabs(result * factor) < fabs(delta))); max_iter -= count; #ifdef BOOST_MATH_INSTRUMENT std::cout << "Halley iteration, final count = " << max_iter << std::endl; #endif return result; }
unsigned hypergeometric_quantile_imp(T p, T q, unsigned r, unsigned n, unsigned N, const Policy& pol) { #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable:4267) #endif typedef typename Policy::discrete_quantile_type discrete_quantile_type; BOOST_MATH_STD_USING BOOST_FPU_EXCEPTION_GUARD T result; T fudge_factor = 1 + tools::epsilon<T>() * ((N <= boost::math::prime(boost::math::max_prime - 1)) ? 50 : 2 * N); unsigned base = static_cast<unsigned>((std::max)(0, (int)(n + r) - (int)(N))); unsigned lim = (std::min)(r, n); BOOST_MATH_INSTRUMENT_VARIABLE(p); BOOST_MATH_INSTRUMENT_VARIABLE(q); BOOST_MATH_INSTRUMENT_VARIABLE(r); BOOST_MATH_INSTRUMENT_VARIABLE(n); BOOST_MATH_INSTRUMENT_VARIABLE(N); BOOST_MATH_INSTRUMENT_VARIABLE(fudge_factor); BOOST_MATH_INSTRUMENT_VARIABLE(base); BOOST_MATH_INSTRUMENT_VARIABLE(lim); if(p <= 0.5) { unsigned x = base; result = hypergeometric_pdf<T>(x, r, n, N, pol); T diff = result; while(result < p) { diff = (diff > tools::min_value<T>() * 8) ? T(n - x) * T(r - x) * diff / (T(x + 1) * T(N + x + 1 - n - r)) : hypergeometric_pdf<T>(x + 1, r, n, N, pol); if(result + diff / 2 > p) break; ++x; result += diff; #ifdef BOOST_MATH_INSTRUMENT if(diff != 0) { BOOST_MATH_INSTRUMENT_VARIABLE(x); BOOST_MATH_INSTRUMENT_VARIABLE(diff); BOOST_MATH_INSTRUMENT_VARIABLE(result); } #endif } return round_x_from_p(x, p, result, fudge_factor, base, lim, discrete_quantile_type()); } else { unsigned x = lim; result = 0; T diff = hypergeometric_pdf<T>(x, r, n, N, pol); while(result + diff / 2 < q) { result += diff; diff = (diff > tools::min_value<T>() * 8) ? x * T(N + x - n - r) * diff / (T(1 + n - x) * T(1 + r - x)) : hypergeometric_pdf<T>(x - 1, r, n, N, pol); --x; #ifdef BOOST_MATH_INSTRUMENT if(diff != 0) { BOOST_MATH_INSTRUMENT_VARIABLE(x); BOOST_MATH_INSTRUMENT_VARIABLE(diff); BOOST_MATH_INSTRUMENT_VARIABLE(result); } #endif } return round_x_from_q(x, q, result, fudge_factor, base, lim, discrete_quantile_type()); } #ifdef BOOST_MSVC # pragma warning(pop) #endif }