inline typename enable_if<is_arithmetic<A>, void>::type eval_atan2(T& result, const A& x, const T& a) { typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type; typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type; cast_type c; c = x; eval_atan2(result, c, a); }
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_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>()); } }