changeset 24448:138c2380521c

Fix failing sort of complex values on Mac platforms (bug #52627). * oct-cmplx.h: Add explanation of the unusual fact that Apple's float version of the constant PI is different from other platforms. Use #if defined with __APPLE__ to determine whether compilation is on a Mac. For Mac platforms, provide a template specialization which overrides the default template code in the case of floats.
author Rik <rik@octave.org>
date Thu, 21 Dec 2017 14:30:38 -0800
parents b431e2719000
children 9a9b2e0596f5
files liboctave/util/oct-cmplx.h
diffstat 1 files changed, 191 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/util/oct-cmplx.h	Thu Dec 21 14:36:06 2017 -0500
+++ b/liboctave/util/oct-cmplx.h	Thu Dec 21 14:30:38 2017 -0800
@@ -31,71 +31,202 @@
 typedef std::complex<double> Complex;
 typedef std::complex<float> FloatComplex;
 
-// For complex-complex and complex-real comparisons, we use the following
-// ordering: compare absolute values first; if they match, compare phase angles.
-// This is partially inconsistent with M*b, which compares complex numbers only
-// by their real parts; OTOH, it uses the same definition for max/min and sort.
-// The abs/arg comparison is definitely more useful (the other one is emulated
-// rather trivially), so let's be consistent and use that all over.
+// For complex-complex and complex-real comparisons, Octave uses the following
+// ordering: compare absolute values first; if they match, compare phase
+// angles.  This is partially inconsistent with M*b, which compares complex
+// numbers only by their real parts; OTOH, it uses the same definition for
+// max/min and sort.  The abs/arg comparison is definitely more useful (the
+// other one is emulated rather trivially), so let's be consistent and use that
+// all over.
 
 // The standard C library function arg() returns [-pi,pi], which creates a
 // non-unique representation for numbers along the negative real axis branch
 // cut.  Change this to principal value (-pi,pi] by mapping -pi to pi.
 
-#define DEF_COMPLEXR_COMP(OP, OPS)                                      \
-  template <typename T>                                                 \
-  inline bool operator OP (const std::complex<T>& a, const std::complex<T>& b) \
-  {                                                                     \
-    OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                    \
-    OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                    \
-    if (ax == bx)                                                       \
-      {                                                                 \
-        OCTAVE_FLOAT_TRUNCATE const T ay = std::arg (a);                \
-        OCTAVE_FLOAT_TRUNCATE const T by = std::arg (b);                \
-        if (ay == static_cast<T> (-M_PI))                               \
-          {                                                             \
-            if (by != static_cast<T> (-M_PI))                           \
-              return static_cast<T> (M_PI) OP by;                       \
-          }                                                             \
-        else if (by == static_cast<T> (-M_PI))                          \
-          {                                                             \
-            return ay OP static_cast<T> (M_PI);                         \
-          }                                                             \
-        return ay OP by;                                                \
-      }                                                                 \
-    else                                                                \
-      return ax OPS bx;                                                 \
-  }                                                                     \
-  template <typename T>                                                 \
-  inline bool operator OP (const std::complex<T>& a, T b)               \
-  {                                                                     \
-    OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                    \
-    OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                    \
-    if (ax == bx)                                                       \
-      {                                                                 \
-        OCTAVE_FLOAT_TRUNCATE const T ay = std::arg (a);                \
-        if (ay == static_cast<T> (-M_PI))                               \
-          return static_cast<T> (M_PI) OP 0;                            \
-        return ay OP 0;                                                 \
-      }                                                                 \
-    else                                                                \
-      return ax OPS bx;                                                 \
-  }                                                                     \
-  template <typename T>                                                 \
-  inline bool operator OP (T a, const std::complex<T>& b)               \
-  {                                                                     \
-    OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                    \
-    OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                    \
-    if (ax == bx)                                                       \
-      {                                                                 \
-        OCTAVE_FLOAT_TRUNCATE const T by = std::arg (b);                \
-        if (by == static_cast<T> (-M_PI))                               \
-          return 0 OP static_cast<T> (M_PI);                            \
-        return 0 OP by;                                                 \
-      }                                                                 \
-    else                                                                \
-      return ax OPS bx;                                                 \
-  }
+#if ! defined (__APPLE__)
+
+   // General templated code for all (double, float) complex operators
+#  define DEF_COMPLEXR_COMP(OP, OPS)                                         \
+     template <typename T>                                                   \
+     inline bool operator OP (const std::complex<T>& a,                      \
+                              const std::complex<T>& b)                      \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                      \
+       OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                      \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const T ay = std::arg (a);                  \
+           OCTAVE_FLOAT_TRUNCATE const T by = std::arg (b);                  \
+           if (ay == static_cast<T> (-M_PI))                                 \
+             {                                                               \
+               if (by != static_cast<T> (-M_PI))                             \
+                 return static_cast<T> (M_PI) OP by;                         \
+             }                                                               \
+           else if (by == static_cast<T> (-M_PI))                            \
+             {                                                               \
+               return ay OP static_cast<T> (M_PI);                           \
+             }                                                               \
+           return ay OP by;                                                  \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }                                                                       \
+     template <typename T>                                                   \
+     inline bool operator OP (const std::complex<T>& a, T b)                 \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                      \
+       OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                      \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const T ay = std::arg (a);                  \
+           if (ay == static_cast<T> (-M_PI))                                 \
+             return static_cast<T> (M_PI) OP 0;                              \
+           return ay OP 0;                                                   \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }                                                                       \
+     template <typename T>                                                   \
+     inline bool operator OP (T a, const std::complex<T>& b)                 \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                      \
+       OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                      \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const T by = std::arg (b);                  \
+           if (by == static_cast<T> (-M_PI))                                 \
+             return 0 OP static_cast<T> (M_PI);                              \
+           return 0 OP by;                                                   \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }
+
+#else
+   // Apple specialization.
+
+   // FIXME: Apple's math library chooses to return a different value for
+   // std::arg with floats than the constant static_cast<float> (M_PI).
+   // Work around this obtuse behavior by providing the constant A_PI which
+   // is Apple's definition of the constant PI for float variables.
+   // The template code for doubles is the same as that for UNIX platforms.
+   // Use C++ template specialization to add specific functions for float
+   // values that make use of A_PI.
+
+   // Apple version of PI
+#  define A_PI 3.1415925025939941f
+
+#  define DEF_COMPLEXR_COMP(OP, OPS)                                         \
+     template <typename T>                                                   \
+     inline bool operator OP (const std::complex<T>& a,                      \
+                              const std::complex<T>& b)                      \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                      \
+       OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                      \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const T ay = std::arg (a);                  \
+           OCTAVE_FLOAT_TRUNCATE const T by = std::arg (b);                  \
+           if (ay == static_cast<T> (-M_PI))                                 \
+             {                                                               \
+               if (by != static_cast<T> (-M_PI))                             \
+                 return static_cast<T> (M_PI) OP by;                         \
+             }                                                               \
+           else if (by == static_cast<T> (-M_PI))                            \
+             {                                                               \
+               return ay OP static_cast<T> (M_PI);                           \
+             }                                                               \
+           return ay OP by;                                                  \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }                                                                       \
+     template <typename T>                                                   \
+     inline bool operator OP (const std::complex<T>& a, T b)                 \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                      \
+       OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                      \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const T ay = std::arg (a);                  \
+           if (ay == static_cast<T> (-M_PI))                                 \
+             return static_cast<T> (M_PI) OP 0;                              \
+           return ay OP 0;                                                   \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }                                                                       \
+     template <typename T>                                                   \
+     inline bool operator OP (T a, const std::complex<T>& b)                 \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const T ax = std::abs (a);                      \
+       OCTAVE_FLOAT_TRUNCATE const T bx = std::abs (b);                      \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const T by = std::arg (b);                  \
+           if (by == static_cast<T> (-M_PI))                                 \
+             return 0 OP static_cast<T> (M_PI);                              \
+           return 0 OP by;                                                   \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }                                                                       \
+     template <>                                                             \
+     inline bool operator OP<float> (const std::complex<float>& a,           \
+                                     const std::complex<float>& b)           \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const float ax = std::abs (a);                  \
+       OCTAVE_FLOAT_TRUNCATE const float bx = std::abs (b);                  \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const float ay = std::arg (a);              \
+           OCTAVE_FLOAT_TRUNCATE const float by = std::arg (b);              \
+           if (ay == -A_PI)                                                  \
+             {                                                               \
+               if (by != -A_PI)                                              \
+                 return static_cast<float> (M_PI) OP by;                     \
+             }                                                               \
+           else if (by == -A_PI)                                             \
+             {                                                               \
+               return ay OP static_cast<float> (M_PI);                       \
+             }                                                               \
+           return ay OP by;                                                  \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }                                                                       \
+     template <>                                                             \
+     inline bool operator OP<float> (const std::complex<float>& a, float b)  \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const float ax = std::abs (a);                  \
+       OCTAVE_FLOAT_TRUNCATE const float bx = std::abs (b);                  \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const float ay = std::arg (a);              \
+           if (ay == -A_PI)                                                  \
+             return static_cast<float> (M_PI) OP 0;                          \
+           return ay OP 0;                                                   \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }                                                                       \
+     template <>                                                             \
+     inline bool operator OP<float> (float a, const std::complex<float>& b)  \
+     {                                                                       \
+       OCTAVE_FLOAT_TRUNCATE const float ax = std::abs (a);                  \
+       OCTAVE_FLOAT_TRUNCATE const float bx = std::abs (b);                  \
+       if (ax == bx)                                                         \
+         {                                                                   \
+           OCTAVE_FLOAT_TRUNCATE const float by = std::arg (b);              \
+           if (by == -A_PI)                                                  \
+             return 0 OP static_cast<float> (M_PI);                          \
+           return 0 OP by;                                                   \
+         }                                                                   \
+       else                                                                  \
+         return ax OPS bx;                                                   \
+     }
+
+#endif
 
 DEF_COMPLEXR_COMP (>, >)
 DEF_COMPLEXR_COMP (<, <)