Mercurial > hg > octave-nkf
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 +++ b/liboctave/util/oct-inttypes.cc @@ -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 +++ b/liboctave/util/oct-inttypes.h @@ -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 +++ b/oct-conf-post.in.h @@ -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