Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r75091 - sandbox/multiprecision/libs/multiprecision/src/functions/elementary
From: e_float_at_[hidden]
Date: 2011-10-22 17:28:29


Author: christopher_kormanyos
Date: 2011-10-22 17:28:28 EDT (Sat, 22 Oct 2011)
New Revision: 75091
URL: http://svn.boost.org/trac/boost/changeset/75091

Log:
- Corrected the handling of NaN's, inf's and zeros for atan2(y, x).
Text files modified:
   sandbox/multiprecision/libs/multiprecision/src/functions/elementary/elementary_trig.cpp | 67 +++++++++++++++++++++++++--------------
   1 files changed, 42 insertions(+), 25 deletions(-)

Modified: sandbox/multiprecision/libs/multiprecision/src/functions/elementary/elementary_trig.cpp
==============================================================================
--- sandbox/multiprecision/libs/multiprecision/src/functions/elementary/elementary_trig.cpp (original)
+++ sandbox/multiprecision/libs/multiprecision/src/functions/elementary/elementary_trig.cpp 2011-10-22 17:28:28 EDT (Sat, 22 Oct 2011)
@@ -451,47 +451,64 @@
 
 mp_float boost::multiprecision::atan2(const mp_float& y, const mp_float& x)
 {
- if((!boost::multiprecision::isfinite(x)) || (!boost::multiprecision::isfinite(y)))
+ // Either x or y is NaN, or both are.
+ if(boost::multiprecision::isnan(x) || boost::multiprecision::isnan(y))
   {
- return x;
+ return std::numeric_limits<mp_float>::quiet_NaN();
   }
 
- // y is zero
- if(boost::multiprecision::iszero(y))
+ const bool x_is_neg = boost::multiprecision::isneg(x);
+ const bool y_is_neg = boost::multiprecision::isneg(y);
+
+ // Both x and y are infinite.
+ if(boost::multiprecision::isinf(x) && boost::multiprecision::isinf(y))
   {
- return (boost::multiprecision::isneg(x) ? boost::multiprecision::pi() : boost::multiprecision::zero());
+ if(x_is_neg)
+ {
+ static const mp_float three_pi_quarter = boost::multiprecision::pi_quarter() * static_cast<boost::int32_t>(3);
+ return ((!y_is_neg) ? three_pi_quarter : -three_pi_quarter);
+ }
+ else
+ {
+ return ((!y_is_neg) ? boost::multiprecision::pi_quarter() : -boost::multiprecision::pi_quarter());
+ }
   }
 
- // x is zero
- if(boost::multiprecision::iszero(x))
+ if(boost::multiprecision::isinf(y)) // AND !isinf(x) and neither x nor y isnan...
   {
- return boost::multiprecision::sgn(y) * boost::multiprecision::pi_half();
+ return ((!y_is_neg) ? boost::multiprecision::pi_half() : -boost::multiprecision::pi_half());
   }
-
- // y is infinite
- if(y.isinf())
+
+ if(boost::multiprecision::isinf(x)) // AND !isinf(y) and neither x nor y isnan...
   {
- const bool b_pos = ((boost::multiprecision::ispos(x) && boost::multiprecision::ispos(y)) || (boost::multiprecision::isneg(x) && boost::multiprecision::isneg(y)));
+ return ((!x_is_neg) ? boost::multiprecision::zero() : boost::multiprecision::pi());
+ }
 
- return (b_pos ? std::numeric_limits<mp_float>::infinity()
- : -std::numeric_limits<mp_float>::infinity());
+ if(boost::multiprecision::iszero(x)) // AND !isnan(y)...
+ {
+ return (boost::multiprecision::iszero(y) ? boost::multiprecision::zero()
+ : ((!y_is_neg) ? boost::multiprecision::pi_half() : -boost::multiprecision::pi_half()));
+ }
+
+ if(boost::multiprecision::iszero(y)) // AND !iszero(x)...
+ {
+ return ((!x_is_neg) ? boost::multiprecision::zero() : boost::multiprecision::pi());
   }
 
- // Compute atan(y / x), ignoring sign.
- mp_float atan_term(boost::multiprecision::atan(y / x));
+ // And finally after all these checks... Compute atan(y / x).
+ // Disregard the signs of x and y at the moment.
+ const mp_float atan_term(boost::multiprecision::atan(y / x));
 
- // Determine quadrant (sign) based on signs of x, y
- const bool y_neg = boost::multiprecision::isneg(y);
- const bool x_neg = boost::multiprecision::isneg(x);
-
- if(y_neg == x_neg)
+ // Determine the quadrant and the corresponding sign of the
+ // result based on the signs of x and y.
+ if(y_is_neg == x_is_neg)
   {
- // Both negative or both positive
- return (x_neg ? atan_term - boost::multiprecision::pi() : atan_term);
+ // Both y and y are negative or both are positive.
+ return (x_is_neg ? (atan_term - boost::multiprecision::pi()) : atan_term);
   }
   else
   {
- // Different signs of x, y
- return (x_neg ? atan_term + boost::multiprecision::pi() : atan_term);
+ // There signs of x and y differ.
+ return (x_is_neg ? (atan_term + boost::multiprecision::pi()) : atan_term);
   }
 }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk