changeset 17993:ac9fd5010620

avoid including gnulib header in installed Octave header file (bug #40607) * oct-conf-post.in.h (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED): New macro. * oct-inttypes.h, oct-inttypes.cc: Don't include fpucw.h from gnulib or the macros it defines. In functions that need to ensure that long double operations are not truncated to double precision, use external functions.
author John W. Eaton <jwe@octave.org>
date Sat, 23 Nov 2013 20:28:46 -0500
parents b8cd17571a1d
children a99b7d656a6c
files liboctave/util/oct-inttypes.cc liboctave/util/oct-inttypes.h oct-conf-post.in.h
diffstat 3 files changed, 232 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/util/oct-inttypes.cc	Sun Nov 24 04:28:35 2013 +0000
+++ b/liboctave/util/oct-inttypes.cc	Sat Nov 23 20:28:46 2013 -0500
@@ -25,6 +25,8 @@
 #include <config.h>
 #endif
 
+#include <fpucw.h>
+
 #include "lo-error.h"
 
 #include "oct-inttypes.h"
@@ -50,7 +52,88 @@
 DECLARE_OCTAVE_INT_TYPENAME (uint32_t, "uint32")
 DECLARE_OCTAVE_INT_TYPENAME (uint64_t, "uint64")
 
-#ifndef OCTAVE_INT_USE_LONG_DOUBLE
+#ifdef OCTAVE_INT_USE_LONG_DOUBLE
+
+#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 ();
+
+   return retval;
+}
+
+#define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(OP) \
+  template OCTAVE_API bool \
+  octave_int_cmp_op::external_mop<octave_int_cmp_op::OP> (long double, \
+                                                          long 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);
+
+uint64_t
+octave_external_uint64_uint64_mul (uint64_t x, uint64_t y)
+{
+  DECL_LONG_DOUBLE_ROUNDING
+
+  BEGIN_LONG_DOUBLE_ROUNDING ();
+
+  uint64_t retval = octave_int_arith_base<uint64_t, false>::mul_internal (x, y);
+
+  END_LONG_DOUBLE_ROUNDING ();
+
+  return retval;
+}
+
+int64_t
+octave_external_int64_int64_mul (int64_t x, int64_t y)
+{
+  DECL_LONG_DOUBLE_ROUNDING
+
+  BEGIN_LONG_DOUBLE_ROUNDING ();
+
+  int64_t retval = octave_int_arith_base<int64_t, true>::mul_internal (x, y);
+
+  END_LONG_DOUBLE_ROUNDING ();
+
+  return retval;
+}
+
+#define OCTAVE_LONG_DOUBLE_OP(OP, NAME) \
+  long double \
+  octave_external_long_double_ ## NAME (long double x, long double y) \
+  { \
+    DECL_LONG_DOUBLE_ROUNDING \
+ \
+    BEGIN_LONG_DOUBLE_ROUNDING (); \
+ \
+    long double retval = x OP y; \
+ \
+    END_LONG_DOUBLE_ROUNDING (); \
+ \
+    return retval; \
+  }
+
+OCTAVE_LONG_DOUBLE_OP (+, add)
+OCTAVE_LONG_DOUBLE_OP (-, sub)
+OCTAVE_LONG_DOUBLE_OP (*, mul)
+OCTAVE_LONG_DOUBLE_OP (/, div)
+
+#endif
+
+#else
 
 // Define comparison operators
 
@@ -142,7 +225,7 @@
 
 template <>
 uint64_t
-octave_int_arith_base<uint64_t, false>::mul (uint64_t x, uint64_t y)
+octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t x, uint64_t y)
 {
   // Get upper words
   uint64_t ux = x >> 32, uy = y >> 32;
@@ -185,7 +268,7 @@
 
 template <>
 int64_t
-octave_int_arith_base<int64_t, true>::mul (int64_t x, int64_t y)
+octave_int_arith_base<int64_t, true>::mul_internal (int64_t x, int64_t y)
 {
   // The signed case is far worse. The problem is that
   // even if neither integer fits into signed 32-bit range, the result may
--- a/liboctave/util/oct-inttypes.h	Sun Nov 24 04:28:35 2013 +0000
+++ b/liboctave/util/oct-inttypes.h	Sat Nov 23 20:28:46 2013 -0500
@@ -29,8 +29,6 @@
 #include <limits>
 #include <iosfwd>
 
-#include <fpucw.h>
-
 #include "lo-traits.h"
 #include "lo-math.h"
 #include "lo-mappers.h"
@@ -176,26 +174,34 @@
   mop (double x, T y)
   { return xop::op (x, static_cast<double> (y)); }
 
+#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
+  template <class xop> static OCTAVE_API bool
+  external_mop (long double, long double);
+#endif
+
   // Typecasting to doubles won't work properly for 64-bit integers --
   // they lose precision.
   // If we have long doubles, use them...
 #ifdef OCTAVE_INT_USE_LONG_DOUBLE
+#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
 #define DEFINE_LONG_DOUBLE_CMP_OP(T1, T2) \
   template <class xop> \
   static bool \
   mop (T1 x, T2 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 external_mop<xop> (static_cast<long double> (x), \
+                              static_cast<long double> (y)); \
+  }
+#else
+#define DEFINE_LONG_DOUBLE_CMP_OP(T1, T2) \
+  template <class xop> \
+  static bool \
+  mop (T1 x, T2 y) \
+  { \
+    return xop::op (static_cast<long double> (x), \
+                    static_cast<long double> (y)); \
+  }
+#endif
 #else
   // ... otherwise, use external handlers
 
@@ -225,13 +231,11 @@
 template <class T>
 class octave_int_base
 {
-protected:
+public:
 
   static T min_val () { return std::numeric_limits<T>:: min (); }
   static T max_val () { return std::numeric_limits<T>:: max (); }
 
-public:
-
   // Convert integer value.
   template <class S>
   static T
@@ -374,8 +378,10 @@
 
   // Multiplication is done using promotion to wider integer type. If there is
   // no suitable promotion type, this operation *MUST* be specialized.
+  static T mul (T x, T y) { return mul_internal (x, y); }
+
   static T
-  mul (T x, T y)
+  mul_internal (T x, T y)
   {
     // Promotion type for multiplication (if exists).
     typedef typename query_integer_type<2*sizeof (T), false>::type mptype;
@@ -416,15 +422,21 @@
 };
 
 #ifdef OCTAVE_INT_USE_LONG_DOUBLE
+
 // Handle 64-bit multiply using long double
+
+#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
+
+extern OCTAVE_API uint64_t
+octave_external_uint64_uint64_mul (uint64_t, uint64_t);
+
+#endif
+
 template <>
 inline uint64_t
-octave_int_arith_base<uint64_t, false>:: mul (uint64_t x, uint64_t y)
+octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t x, uint64_t y)
 {
   uint64_t retval;
-  DECL_LONG_DOUBLE_ROUNDING
-
-  BEGIN_LONG_DOUBLE_ROUNDING ();
 
   long double p = static_cast<long double> (x) * static_cast<long double> (y);
 
@@ -433,15 +445,27 @@
   else
     retval = static_cast<uint64_t> (p);
 
-  END_LONG_DOUBLE_ROUNDING ();
-
   return retval;
 }
+
+template <>
+inline uint64_t
+octave_int_arith_base<uint64_t, false>::mul (uint64_t x, uint64_t y)
+{
+#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
+  return octave_external_uint64_uint64_mul (x, y);
 #else
+  return mul_internal (x, y);
+#endif
+}
+
+#else
+
 // Special handler for 64-bit integer multiply.
 template <>
 OCTAVE_API uint64_t
-octave_int_arith_base<uint64_t, false>::mul (uint64_t, uint64_t);
+octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t, uint64_t);
+
 #endif
 
 // Signed integer arithmetics.
@@ -637,8 +661,10 @@
 
   // Multiplication is done using promotion to wider integer type. If there is
   // no suitable promotion type, this operation *MUST* be specialized.
+  static T mul (T x, T y) { return mul_internal (x, y); }
+
   static T
-  mul (T x, T y)
+  mul_internal (T x, T y)
   {
     // Promotion type for multiplication (if exists).
     typedef typename query_integer_type<2*sizeof (T), true>::type mptype;
@@ -712,15 +738,21 @@
 };
 
 #ifdef OCTAVE_INT_USE_LONG_DOUBLE
+
 // Handle 64-bit multiply using long double
+
+#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
+
+extern OCTAVE_API int64_t
+octave_external_int64_int64_mul (int64_t, int64_t);
+
+#endif
+
 template <>
 inline int64_t
-octave_int_arith_base<int64_t, true>:: mul (int64_t x, int64_t y)
+octave_int_arith_base<int64_t, true>::mul_internal (int64_t x, int64_t y)
 {
-  uint64_t retval;
-  DECL_LONG_DOUBLE_ROUNDING
-
-  BEGIN_LONG_DOUBLE_ROUNDING ();
+  int64_t retval;
 
   long double p = static_cast<long double> (x) * static_cast<long double> (y);
 
@@ -734,15 +766,27 @@
   else
     retval = static_cast<int64_t> (p);
 
-  END_LONG_DOUBLE_ROUNDING ();
-
   return retval;
 }
+
+template <>
+inline int64_t
+octave_int_arith_base<int64_t, true>::mul (int64_t x, int64_t y)
+{
+#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
+  return octave_external_int64_int64_mul (x, y);
 #else
+  return mul_internal (x, y);
+#endif
+}
+
+#else
+
 // Special handler for 64-bit integer multiply.
 template <>
 OCTAVE_API int64_t
-octave_int_arith_base<int64_t, true>::mul (int64_t, int64_t);
+octave_int_arith_base<int64_t, true>::mul_internal (int64_t, int64_t);
+
 #endif
 
 // This class simply selects the proper arithmetics.
@@ -993,6 +1037,18 @@
 typedef octave_int<uint32_t> octave_uint32;
 typedef octave_int<uint64_t> octave_uint64;
 
+extern OCTAVE_API long double
+octave_external_long_double_add (long double x, long double y);
+
+extern OCTAVE_API long double
+octave_external_long_double_sub (long double x, long double y);
+
+extern OCTAVE_API long double
+octave_external_long_double_mul (long double x, long double y);
+
+extern OCTAVE_API long double
+octave_external_long_double_div (long double x, long double y);
+
 #define OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
   template <class T> \
   inline octave_int<T> \
@@ -1005,56 +1061,76 @@
 
 #ifdef OCTAVE_INT_USE_LONG_DOUBLE
 // Handle mixed op using long double
-#define OCTAVE_INT_DOUBLE_BIN_OP(OP) \
+#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
+#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
   OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
   template <> \
   inline octave_int64 \
   operator OP (const double& x, const octave_int64& y) \
   { \
-    octave_int64 retval; \
-    DECL_LONG_DOUBLE_ROUNDING \
-    BEGIN_LONG_DOUBLE_ROUNDING (); \
-    retval = octave_int64 (x OP static_cast<long double> (y.value ())); \
-    END_LONG_DOUBLE_ROUNDING (); \
-    return retval; \
+    return octave_int64 \
+      (octave_external_long_double_ ## NAME \
+       (static_cast<long double> (x), \
+        static_cast<long double> (y.value ()))); \
   } \
   template <> \
   inline octave_uint64 \
   operator OP (const double& x, const octave_uint64& y) \
   { \
-    octave_uint64 retval; \
-    DECL_LONG_DOUBLE_ROUNDING \
-    BEGIN_LONG_DOUBLE_ROUNDING (); \
-    retval = octave_uint64 (x OP static_cast<long double> (y.value ())); \
-    END_LONG_DOUBLE_ROUNDING (); \
-    return retval; \
+    return octave_uint64 \
+      (octave_external_long_double_ ## NAME \
+       (static_cast<long double> (x), \
+        static_cast<long double> (y.value ()))); \
   } \
   template <> \
   inline octave_int64 \
   operator OP (const octave_int64& x, const double& y) \
   { \
-    octave_int64 retval; \
-    DECL_LONG_DOUBLE_ROUNDING \
-    BEGIN_LONG_DOUBLE_ROUNDING (); \
-    retval = octave_int64 (static_cast<long double> (x.value ()) OP y);   \
-    END_LONG_DOUBLE_ROUNDING (); \
-    return retval; \
+    return octave_int64 \
+      (octave_external_long_double_ ## NAME \
+       (static_cast<long double> (x.value ()), \
+        static_cast<long double> (y))); \
   } \
   template <> \
   inline octave_uint64 \
   operator OP (const octave_uint64& x, const double& y) \
   { \
-    octave_uint64 retval; \
-    DECL_LONG_DOUBLE_ROUNDING \
-    BEGIN_LONG_DOUBLE_ROUNDING (); \
-    retval = octave_uint64 (static_cast<long double> (x.value ()) OP y); \
-    END_LONG_DOUBLE_ROUNDING (); \
-    return retval; \
+    return octave_uint64 \
+      (octave_external_long_double_ ## NAME \
+       (static_cast<long double> (x.value ()), \
+        static_cast<long double> (y))); \
   }
-
+#else
+#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
+  OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
+  template <> \
+  inline octave_int64 \
+  operator OP (const double& x, const octave_int64& y) \
+  { \
+    return octave_int64 (x OP static_cast<long double> (y.value ())); \
+  } \
+  template <> \
+  inline octave_uint64 \
+  operator OP (const double& x, const octave_uint64& y) \
+  { \
+    return octave_uint64 (x OP static_cast<long double> (y.value ())); \
+  } \
+  template <> \
+  inline octave_int64 \
+  operator OP (const octave_int64& x, const double& y) \
+  { \
+    return octave_int64 (static_cast<long double> (x.value ()) OP y);   \
+  } \
+  template <> \
+  inline octave_uint64 \
+  operator OP (const octave_uint64& x, const double& y) \
+  { \
+    return octave_uint64 (static_cast<long double> (x.value ()) OP y); \
+  }
+#endif
 #else
 // external handlers
-#define OCTAVE_INT_DOUBLE_BIN_OP(OP) \
+#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
   OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
   template <> \
   OCTAVE_API octave_int64 \
@@ -1071,10 +1147,10 @@
 
 #endif
 
-OCTAVE_INT_DOUBLE_BIN_OP (+)
-OCTAVE_INT_DOUBLE_BIN_OP (-)
-OCTAVE_INT_DOUBLE_BIN_OP (*)
-OCTAVE_INT_DOUBLE_BIN_OP (/)
+OCTAVE_INT_DOUBLE_BIN_OP (+, add)
+OCTAVE_INT_DOUBLE_BIN_OP (-, sub)
+OCTAVE_INT_DOUBLE_BIN_OP (*, mul)
+OCTAVE_INT_DOUBLE_BIN_OP (/, div)
 
 #undef OCTAVE_INT_DOUBLE_BIN_OP0
 #undef OCTAVE_INT_DOUBLE_BIN_OP
--- a/oct-conf-post.in.h	Sun Nov 24 04:28:35 2013 +0000
+++ b/oct-conf-post.in.h	Sat Nov 23 20:28:46 2013 -0500
@@ -107,7 +107,11 @@
    them at least 80 bits wide and we need roundl declared in math.h.
    FIXME: Maybe substitute this by a more precise check in the future?  */
 #if (SIZEOF_LONG_DOUBLE >= 10) && defined (HAVE_ROUNDL)
-#define OCTAVE_INT_USE_LONG_DOUBLE
+# define OCTAVE_INT_USE_LONG_DOUBLE
+# if (SIZEOF_LONG_DOUBLE == 10 \
+      && (defined __i386__ || defined __x86_64__) && defined __GNUC__)
+#define OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED 1
+# endif
 #endif
 
 #define OCTAVE_EMPTY_CPP_ARG