diff liboctave/util/oct-inttypes.cc @ 18017:0cd39f7f2409 stable

additional improvements for int64 ops implemented with long double (bug #40607) * oct-inttypes.h, oct-inttypes.cc: Ensure that conversions between 64-bit integer and long double are performed when long double rounding rules are in effect.
author John W. Eaton <jwe@octave.org>
date Tue, 26 Nov 2013 02:04:10 -0500
parents 79653c5b6147
children 8e056300994b c644ed73c6ce
line wrap: on
line diff
--- a/liboctave/util/oct-inttypes.cc
+++ b/liboctave/util/oct-inttypes.cc
@@ -56,32 +56,58 @@
 
 #ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
 
-template <class xop>
-bool
-octave_int_cmp_op::external_mop (long double x, long double y)
-{
-   DECL_LONG_DOUBLE_ROUNDING
-
-   BEGIN_LONG_DOUBLE_ROUNDING ();
-
-   bool retval = xop::op (x, y);
-
-   END_LONG_DOUBLE_ROUNDING ();
+#define DEFINE_OCTAVE_LONG_DOUBLE_CMP_OP_TEMPLATES(T) \
+  template <class xop> \
+  bool \
+  octave_int_cmp_op::external_mop (double x, T y) \
+  { \
+     DECL_LONG_DOUBLE_ROUNDING \
+   \
+     BEGIN_LONG_DOUBLE_ROUNDING (); \
+   \
+     bool retval = xop::op (static_cast<long double> (x), \
+                            static_cast<long double> (y)); \
+   \
+     END_LONG_DOUBLE_ROUNDING (); \
+   \
+     return retval; \
+  } \
+   \
+  template <class xop> \
+  bool \
+  octave_int_cmp_op::external_mop (T x, double y) \
+  { \
+     DECL_LONG_DOUBLE_ROUNDING \
+   \
+     BEGIN_LONG_DOUBLE_ROUNDING (); \
+   \
+     bool retval = xop::op (static_cast<long double> (x), \
+                            static_cast<long double> (y)); \
+   \
+     END_LONG_DOUBLE_ROUNDING (); \
+   \
+     return retval; \
+  }
 
-   return retval;
-}
+DEFINE_OCTAVE_LONG_DOUBLE_CMP_OP_TEMPLATES (int64_t)
+DEFINE_OCTAVE_LONG_DOUBLE_CMP_OP_TEMPLATES (uint64_t)
 
-#define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(OP) \
+#define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(OP, T) \
+  template OCTAVE_API bool \
+  octave_int_cmp_op::external_mop<octave_int_cmp_op::OP> (double, T); \
   template OCTAVE_API bool \
-  octave_int_cmp_op::external_mop<octave_int_cmp_op::OP> (long double, \
-                                                          long double)
+  octave_int_cmp_op::external_mop<octave_int_cmp_op::OP> (T, double)
 
-INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(lt);
-INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(le);
-INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(gt);
-INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(ge);
-INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(eq);
-INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(ne);
+#define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OPS(T) \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (lt, T); \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (le, T); \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (gt, T); \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (ge, T); \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (eq, T); \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (ne, T)
+
+INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OPS (int64_t);
+INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OPS (uint64_t);
 
 uint64_t
 octave_external_uint64_uint64_mul (uint64_t x, uint64_t y)
@@ -116,27 +142,43 @@
 // which can happen after we end long double rounding.  Attempt to avoid
 // that problem by storing the full precision temporary value in the
 // integer value before we end the long double rounding mode.
+// Similarly, the conversion from the 64-bit integer type to long double
+// must also occur in long double rounding mode.
 
-#define OCTAVE_LONG_DOUBLE_OP(RT, OP, NAME) \
-  RT \
-  RT ## _external_long_double_ ## NAME (long double x, long double y) \
+#define OCTAVE_LONG_DOUBLE_OP(T, OP, NAME) \
+  T \
+  external_double_ ## T ## _ ## NAME (double x, T y) \
   { \
     DECL_LONG_DOUBLE_ROUNDING \
  \
     BEGIN_LONG_DOUBLE_ROUNDING (); \
  \
-    RT retval = RT (x OP y); \
+    T retval = T (x OP static_cast<long double> (y.value ())); \
+ \
+    END_LONG_DOUBLE_ROUNDING (); \
+ \
+    return retval; \
+  } \
+ \
+  T \
+  external_ ## T ## _double_ ## NAME (T x, double y) \
+  { \
+    DECL_LONG_DOUBLE_ROUNDING \
+ \
+    BEGIN_LONG_DOUBLE_ROUNDING (); \
+ \
+    T retval = T (static_cast<long double> (x.value ()) OP y); \
  \
     END_LONG_DOUBLE_ROUNDING (); \
  \
     return retval; \
   }
 
-#define OCTAVE_LONG_DOUBLE_OPS(RT) \
-  OCTAVE_LONG_DOUBLE_OP (RT, +, add); \
-  OCTAVE_LONG_DOUBLE_OP (RT, -, sub); \
-  OCTAVE_LONG_DOUBLE_OP (RT, *, mul); \
-  OCTAVE_LONG_DOUBLE_OP (RT, /, div)
+#define OCTAVE_LONG_DOUBLE_OPS(T) \
+  OCTAVE_LONG_DOUBLE_OP (T, +, add); \
+  OCTAVE_LONG_DOUBLE_OP (T, -, sub); \
+  OCTAVE_LONG_DOUBLE_OP (T, *, mul); \
+  OCTAVE_LONG_DOUBLE_OP (T, /, div)
 
 OCTAVE_LONG_DOUBLE_OPS(octave_int64);
 OCTAVE_LONG_DOUBLE_OPS(octave_uint64);