lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master c07baf8 6/7: Conditionalize x87 code; provide


From: Greg Chicares
Subject: [lmi-commits] [lmi] master c07baf8 6/7: Conditionalize x87 code; provide <cfenv> alternatives where possible
Date: Thu, 5 Jan 2017 03:41:39 +0000 (UTC)

branch: master
commit c07baf864b6e45193a679113f695a0e9c0332551
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Conditionalize x87 code; provide <cfenv> alternatives where possible
---
 fenv_lmi.cpp           |   81 ++++++++++++++++++++++++------------------------
 fenv_lmi.hpp           |   24 ++------------
 fenv_lmi_test.cpp      |   16 +++++-----
 fenv_lmi_x86.hpp       |    4 +--
 math_functors_test.cpp |    4 ++-
 round_test.cpp         |   40 +++---------------------
 round_to_test.cpp      |   57 +++-------------------------------
 skeleton.cpp           |    4 +++
 8 files changed, 67 insertions(+), 163 deletions(-)

diff --git a/fenv_lmi.cpp b/fenv_lmi.cpp
index bb68bc4..6cc1e25 100644
--- a/fenv_lmi.cpp
+++ b/fenv_lmi.cpp
@@ -24,6 +24,8 @@
 #include "fenv_lmi.hpp"
 
 #include "alert.hpp"
+#include "assert_lmi.hpp"
+#include "miscellany.hpp"               // stifle_warning_for_unused_variable()
 
 #include <iomanip>
 #include <ios>
@@ -59,23 +61,17 @@ namespace floating_point_environment {} // doxygen 
workaround.
 
 void fenv_initialize()
 {
-#if defined LMI_X86
+#if defined LMI_X87
     x87_control_word(default_x87_control_word());
-#elif defined LMI_IEC_559
+#else  // !defined LMI_X87
     fenv_t save_env;
     feholdexcept(&save_env);
     fesetround(FE_TONEAREST);
-#   if defined __MINGW32__
     // Standard C++ provides no way to set hardware precision.
     // Here is an example of a C99 7.6/9 extension that controls
     // hardware precision for MinGW32:
     //   fesetenv(FE_PC64_ENV);
-#   else  // !defined __MINGW32__
-#       error Find a platform-specific way to set hardware precision.
-#   endif // !defined __MINGW32__
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
+#endif // !defined LMI_X87
 }
 
 e_ieee754_precision fenv_precision()
@@ -88,7 +84,7 @@ e_ieee754_precision fenv_precision()
         : (PC_64 == pc) ? fe_ldblprec
         : throw std::runtime_error("Failed to determine hardware precision.")
         ;
-#elif defined LMI_X86
+#elif defined LMI_X87
     e_x87_precision pc = intel_control_word(x87_control_word()).pc();
     return
           (x87_fe_fltprec  == pc) ? fe_fltprec
@@ -96,9 +92,11 @@ e_ieee754_precision fenv_precision()
         : (x87_fe_ldblprec == pc) ? fe_ldblprec
         : throw std::runtime_error("Failed to determine hardware precision.")
         ;
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
+#else  // !defined LMI_X87
+    // Assume that any reasonable platform other than x87 uses
+    // double-precision floating point by default.
+    return fe_dblprec;
+#endif // !defined LMI_X87
 }
 
 void fenv_precision(e_ieee754_precision precision_mode)
@@ -111,7 +109,7 @@ void fenv_precision(e_ieee754_precision precision_mode)
         : throw std::runtime_error("Failed to set hardware precision.")
         ;
     _control87(z, MCW_PC);
-#elif defined LMI_X86
+#elif defined LMI_X87
     e_x87_precision pc =
           (fe_fltprec  == precision_mode) ? x87_fe_fltprec
         : (fe_dblprec  == precision_mode) ? x87_fe_dblprec
@@ -121,9 +119,9 @@ void fenv_precision(e_ieee754_precision precision_mode)
     intel_control_word control_word(x87_control_word());
     control_word.pc(pc);
     x87_control_word(control_word.cw());
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
+#else  // !defined LMI_X87
+    throw std::logic_error("Unable to set hardware precision.");
+#endif // !defined LMI_X87
 }
 
 e_ieee754_rounding fenv_rounding()
@@ -137,7 +135,7 @@ e_ieee754_rounding fenv_rounding()
         : (RC_CHOP == rc) ? fe_towardzero
         : throw std::runtime_error("Failed to determine rounding mode.")
         ;
-#elif defined LMI_X86
+#elif defined LMI_X87
     e_x87_rounding rc = intel_control_word(x87_control_word()).rc();
     return
           (x87_fe_tonearest  == rc) ? fe_tonearest
@@ -146,7 +144,7 @@ e_ieee754_rounding fenv_rounding()
         : (x87_fe_towardzero == rc) ? fe_towardzero
         : throw std::runtime_error("Failed to determine rounding mode.")
         ;
-#elif defined LMI_IEC_559
+#else  // !defined LMI_X87
     int z = fegetround();
     return
           (FE_TONEAREST  == z) ? fe_tonearest
@@ -155,9 +153,7 @@ e_ieee754_rounding fenv_rounding()
         : (FE_TOWARDZERO == z) ? fe_towardzero
         : throw std::runtime_error("Failed to determine rounding mode.")
         ;
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
+#endif // !defined LMI_X87
 }
 
 void fenv_rounding(e_ieee754_rounding rounding_mode)
@@ -171,7 +167,7 @@ void fenv_rounding(e_ieee754_rounding rounding_mode)
         : throw std::runtime_error("Failed to set rounding mode.")
         ;
     _control87(z, MCW_RC);
-#elif defined LMI_X86
+#elif defined LMI_X87
     e_x87_rounding rc =
           (fe_tonearest  == rounding_mode) ? x87_fe_tonearest
         : (fe_downward   == rounding_mode) ? x87_fe_downward
@@ -182,7 +178,7 @@ void fenv_rounding(e_ieee754_rounding rounding_mode)
     intel_control_word control_word(x87_control_word());
     control_word.rc(rc);
     x87_control_word(control_word.cw());
-#elif defined LMI_IEC_559
+#else  // !defined LMI_X87
     int z =
           (fe_tonearest  == rounding_mode) ? FE_TONEAREST
         : (fe_downward   == rounding_mode) ? FE_DOWNWARD
@@ -191,18 +187,16 @@ void fenv_rounding(e_ieee754_rounding rounding_mode)
         : throw std::runtime_error("Failed to set rounding mode.")
         ;
     fesetround(z);
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
+#endif // !defined LMI_X87
 }
 
 bool fenv_is_valid()
 {
-#if defined LMI_X86
+#if defined LMI_X87
     return default_x87_control_word() == x87_control_word();
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
+#else  // !defined LMI_X87
+    return fe_tonearest == fegetround() && 0 == fetestexcept(FE_ALL_EXCEPT);
+#endif // !defined LMI_X87
 }
 
 namespace
@@ -210,15 +204,22 @@ namespace
 std::string fenv_explain_invalid_control_word()
 {
     std::ostringstream oss;
+#if defined LMI_X87
     oss
         << "The floating-point control word was unexpectedly '"
         << std::hex << std::internal << std::showbase << std::setfill('0')
-#if defined LMI_X86
         << std::setw(6) << x87_control_word()
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
-        << "'."
+        << "'.\n"
+        ;
+#else  // !defined LMI_X87
+    oss
+        << "The floating-point environment unexpectedly changed."
+        << "\nThe rounding mode is " << fegetround()
+        << " and the exception bitmask is " << fetestexcept(FE_ALL_EXCEPT)
+        << ".\n"
+        ;
+#endif // !defined LMI_X87
+    oss
         << "\nProbably some other program changed this crucial setting."
         << "\nIt has been reset correctly. Rerun any illustration that"
         << "\nwas being run when this message appeared, because it may"
@@ -250,17 +251,17 @@ std::string fenv_explain_invalid_control_word()
 
 bool fenv_validate(enum_fenv_indulgence indulgence)
 {
+#if defined LMI_X87
     if
         (   e_fenv_indulge_0x027f == indulgence
-#if defined LMI_X86
         &&  e_fenv_indulge_0x027f == x87_control_word()
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
         )
         {
         fenv_initialize();
         }
+#else  // !defined LMI_X87
+    stifle_warning_for_unused_variable(indulgence);
+#endif // !defined LMI_X87
 
     bool okay = fenv_is_valid();
 
diff --git a/fenv_lmi.hpp b/fenv_lmi.hpp
index aec4fb4..bdd77d6 100644
--- a/fenv_lmi.hpp
+++ b/fenv_lmi.hpp
@@ -26,29 +26,9 @@
 
 #include "so_attributes.hpp"
 
-#if defined LMI_X86
+#if defined LMI_X87
 #   include "fenv_lmi_x86.hpp"
-#else  // Unknown compiler or platform.
-#   error Unknown compiler or platform.
-#endif // Unknown compiler or platform.
-
-// SOMEDAY !! Revisit suppressed __STDC_IEC_559__ support. See:
-//   http://lists.nongnu.org/archive/html/lmi/2008-06/msg00033.html
-#if defined LMI_IEC_559
-// In case the C++ compiler supports C99 7.6 facilities, assume that
-// it defines __STDC_IEC_559__ (except that MinGW supports some such
-// facilities but defines no such macro), and puts prototypes in
-// <fenv.h> but not in namespace std.
-#   include <fenv.h>
-#   if defined __GNUC__ && LMI_GCC_VERSION <= 40300
-// As of 2007-07-05, the gcc manual here:
-//   http://gcc.gnu.org/onlinedocs/gcc/Floating-point-implementation.html
-// which "corresponds to GCC version 4.3.0" says "This pragma is not
-// implemented".
-#   else  // Pragma STDC FENV_ACCESS implemented.
-#       pragma STDC FENV_ACCESS ON
-#   endif // Pragma STDC FENV_ACCESS implemented.
-#endif // defined LMI_IEC_559
+#endif // defined LMI_X87
 
 #include <cfenv>
 
diff --git a/fenv_lmi_test.cpp b/fenv_lmi_test.cpp
index 3fce81e..494c79b 100644
--- a/fenv_lmi_test.cpp
+++ b/fenv_lmi_test.cpp
@@ -41,10 +41,6 @@
 
 #include <bitset>
 #include <climits>                      // CHAR_BIT
-#if defined LMI_IEC_559 || defined __MINGW32__
-// Specify '|| defined __MINGW32__' to test MinGW extensions like FE_PC64_ENV.
-#   include <fenv.h>
-#endif // defined LMI_IEC_559
 #include <math.h>                       // C99 rint()
 #include <stdexcept>
 
@@ -67,7 +63,7 @@ std::bitset<CHAR_BIT * sizeof(unsigned long int)> 
bits(unsigned long int i)
 
 int test_main(int, char*[])
 {
-#if defined LMI_X86
+#if defined LMI_X87
     unsigned short int cw = 0x0000;
 
     BOOST_TEST_EQUAL_BITS(0x037f, msvc_to_intel(0x0008001f));
@@ -168,12 +164,11 @@ int test_main(int, char*[])
     fenv_rounding(fe_towardzero);
     BOOST_TEST_EQUAL_BITS(0x0f7f, x87_control_word());
 
-#else  // Unknown platform.
-    throw std::runtime_error("Unknown platform.");
-#endif // Unknown platform.
+#endif // defined LMI_X87
 
-    // Test precision control.
+    // Test precision control iff supported.
 
+#if defined LMI_X87
     fenv_precision  (fe_fltprec);
     BOOST_TEST_EQUAL(fe_fltprec , fenv_precision());
 
@@ -182,6 +177,7 @@ int test_main(int, char*[])
 
     fenv_precision  (fe_ldblprec);
     BOOST_TEST_EQUAL(fe_ldblprec, fenv_precision());
+#endif // defined LMI_X87
 
     // Test rounding control.
 
@@ -227,6 +223,7 @@ int test_main(int, char*[])
     fenv_initialize();
     BOOST_TEST(fenv_validate());
 
+#if defined LMI_X87
     std::cout
         << "Expect induced warnings exactly as predicted below,"
         << " but no test failure."
@@ -269,6 +266,7 @@ int test_main(int, char*[])
     BOOST_TEST(0 == fenv_guard::instance_count());
     std::cout << "...end of induced warning]." << std::endl;
     BOOST_TEST(fenv_validate());
+#endif // defined LMI_X87
 
     return 0;
 }
diff --git a/fenv_lmi_x86.hpp b/fenv_lmi_x86.hpp
index 775c137..e123444 100644
--- a/fenv_lmi_x86.hpp
+++ b/fenv_lmi_x86.hpp
@@ -31,7 +31,7 @@
 #   include <float.h>                   // nonstandard _control87()
 #endif // defined __BORLANDC__ || defined _MSC_VER
 
-#if defined LMI_X86
+#if defined LMI_X87
 /// These functions manipulate the x86 fpu (x87) control word. This
 /// shouldn't be as difficult as it actually is. Part of the problem
 /// is that C was strangely slow to adopt sophisticated numerics:
@@ -348,7 +348,7 @@ inline void x87_control_word(unsigned short int cw)
 #   endif // Unknown compiler or platform.
 }
 
-#endif // LMI_X86
+#endif // defined LMI_X87
 
 #endif // fenv_lmi_x86_hpp
 
diff --git a/math_functors_test.cpp b/math_functors_test.cpp
index 6a00d0b..f747d3b 100644
--- a/math_functors_test.cpp
+++ b/math_functors_test.cpp
@@ -140,7 +140,7 @@ struct coi_rate_from_q_naive
 /// This function isn't a unit test per se. Its purpose is to show
 /// how a sample calculation is affected by
 ///   exponential versus power method, and
-///   hardware precision.
+///   hardware precision (on supported platforms).
 ///
 /// Define f(i,m) = (1+i)^(1/m) - 1, i.e., "i upper m over m".
 /// Let i0 = 0.0004 (forty bp).
@@ -150,6 +150,7 @@ struct coi_rate_from_q_naive
 void sample_results()
 {
     fenv_initialize();
+#if defined LMI_X87
     fenv_precision(fe_ldblprec);
     std::cout
         << "\n  annual rate corresponding to a 0.004 daily spread"
@@ -163,6 +164,7 @@ void sample_results()
 
     fenv_initialize();
     fenv_precision(fe_dblprec);
+#endif // defined LMI_X87
     std::cout
         << std::setprecision(20)
         << "    double precision, expm1l and log1pl\n      "
diff --git a/round_test.cpp b/round_test.cpp
index dddbcd3..f4dcf43 100644
--- a/round_test.cpp
+++ b/round_test.cpp
@@ -44,24 +44,6 @@
 #include <math.h>                       // C99 round() and kin
 #include <ostream>
 
-#if defined LMI_IEC_559
-    // In case the C++ compiler offers C99 fesetround(), assume that
-    // it defines __STDC_IEC_559__, but doesn't support
-    //   #pragma STDC FENV_ACCESS ON
-    // in C++ mode. (I have no such compiler, so that assumption and
-    // code that ought to use that pragma are untested.)
-    enum e_ieee754_rounding
-        {fe_tonearest  = FE_TONEAREST
-        ,fe_downward   = FE_DOWNWARD
-        ,fe_upward     = FE_UPWARD
-        ,fe_towardzero = FE_TOWARDZERO
-        };
-#elif defined LMI_X86
-    // "fenv_lmi_x86.hpp" provides the necessary values.
-#else  // No known way to set rounding style.
-#   error No known way to set rounding style.
-#endif // No known way to set rounding style.
-
 // Print name of software rounding style for diagnostics.
 char const* get_name_of_style(rounding_style style)
 {
@@ -112,21 +94,7 @@ template<> char const* get_name_of_float_type<long double>()
 
 void set_hardware_rounding_mode(e_ieee754_rounding mode, bool synchronize)
 {
-#if defined LMI_IEC_559
-    fesetround(mode);
-#elif defined LMI_X86_64
-    // See the parallel section of 'round_to_test.cpp'.
-    // For the nonce, set both i87 and SSE rounding modes here.
-    fesetround(mode);
-    fenv_rounding(mode);
-#elif defined LMI_X86
     fenv_rounding(mode);
-#else // No known way to set hardware rounding mode.
-    std::cerr
-        << "\nCannot set floating-point hardware rounding mode.\n"
-        << "Results may be invalid.\n"
-        ;
-#endif // No known way to set hardware rounding mode.
 
     if(synchronize)
         {
@@ -177,13 +145,13 @@ void print_hex_val(T t, char const* name)
   std::cout << "hex value of " << name << " is: ";
 
 // GWC modifications begin
-  // My principal compiler, mingw gcc, has sizeof(long double) == 12,
-  // but only ten bytes are significant; the other two are padding.
+  // For gcc with x87, sizeof(long double) == 12, but only
+  // ten bytes are significant--the other two are padding.
   std::size_t size_of_T = sizeof(T);
-#if defined __GNUC__ && defined LMI_X86
+#if defined __GNUC__ && defined LMI_X87
   if(12 == size_of_T)
     size_of_T = 10;
-#endif // defined __GNUC__ && defined LMI_X86
+#endif // defined __GNUC__ && defined LMI_X87
 // GWC modifications end
 
   for (unsigned int i = 0; i < size_of_T; ++i) { // modified by GWC
diff --git a/round_to_test.cpp b/round_to_test.cpp
index 0beb26d..a3465d0 100644
--- a/round_to_test.cpp
+++ b/round_to_test.cpp
@@ -32,41 +32,6 @@
 #include <iostream>
 #include <ostream>
 
-#if defined LMI_IEC_559
-    // The 'LMI_IEC_559' macro is never defined by any source file or
-    // by any makefile, so this conditional block is not reached today.
-    // For the macro's original rationale, see:
-    //   http://lists.nongnu.org/archive/html/lmi/2008-06/msg00034.html
-    // The description that follows is outdated anyway, because C++11
-    // now provides <cfenv>.
-    //
-    // In case the C++ compiler offers C99 fesetround(), assume that
-    // it defines __STDC_IEC_559__, but doesn't support
-    //   #pragma STDC FENV_ACCESS ON
-    // in C++ mode. (I have no such compiler, so that assumption and
-    // code that ought to use that pragma are untested.)
-    enum e_ieee754_rounding
-        {fe_tonearest  = FE_TONEAREST
-        ,fe_downward   = FE_DOWNWARD
-        ,fe_upward     = FE_UPWARD
-        ,fe_towardzero = FE_TOWARDZERO
-        };
-#elif defined LMI_X86_64
-    // Probably this conditional should distinguish SSE from x87,
-    // rather than 64- from 32-bit x64. For the nonce, this prevents
-    // certain unit-test failures noted here:
-    //   http://lists.nongnu.org/archive/html/lmi/2016-12/msg00053.html
-#   include <cfenv>
-#elif defined LMI_X86
-    // It seems at first that the conditional here should be LMI_X86_32
-    // because x86_64 is treated above. However, perhaps the actual
-    // distinction is between SSE above and x87 here.
-    //
-    // "fenv_lmi_x86.hpp" provides the necessary values.
-#else  // No known way to set rounding style.
-#   error No known way to set rounding style.
-#endif // No known way to set rounding style.
-
 // Print name of software rounding style for diagnostics.
 char const* get_name_of_style(rounding_style style)
 {
@@ -117,21 +82,7 @@ template<> char const* get_name_of_float_type<long double>()
 
 void set_hardware_rounding_mode(e_ieee754_rounding mode, bool synchronize)
 {
-#if defined LMI_IEC_559
-    fesetround(mode);
-#elif defined LMI_X86_64
-    // See comments above on the <cfenv> series of conditionals.
-    // For the nonce, set both i87 and SSE rounding modes here.
-    fesetround(mode);
     fenv_rounding(mode);
-#elif defined LMI_X86
-    fenv_rounding(mode);
-#else // No known way to set hardware rounding mode.
-    std::cerr
-        << "\nCannot set floating-point hardware rounding mode.\n"
-        << "Results may be invalid.\n"
-        ;
-#endif // No known way to set hardware rounding mode.
 
     if(synchronize)
         {
@@ -182,13 +133,13 @@ void print_hex_val(T t, char const* name)
   std::cout << "hex value of " << name << " is: ";
 
 // GWC modifications begin
-  // My principal compiler, mingw gcc, has sizeof(long double) == 12,
-  // but only ten bytes are significant; the other two are padding.
+  // For gcc with x87, sizeof(long double) == 12, but only
+  // ten bytes are significant--the other two are padding.
   std::size_t size_of_T = sizeof(T);
-#if defined __GNUC__ && defined LMI_X86
+#if defined __GNUC__ && defined LMI_X87
   if(12 == size_of_T)
     size_of_T = 10;
-#endif // defined __GNUC__ && defined LMI_X86
+#endif // defined __GNUC__ && defined LMI_X87
 // GWC modifications end
 
   for (unsigned int i = 0; i < size_of_T; ++i) { // modified by GWC
diff --git a/skeleton.cpp b/skeleton.cpp
index debacac..068a855 100644
--- a/skeleton.cpp
+++ b/skeleton.cpp
@@ -1026,6 +1026,7 @@ void Skeleton::UponTestDateConversions(wxCommandEvent&)
 
 void Skeleton::UponTestFloatingPointEnvironment(wxCommandEvent&)
 {
+#if defined LMI_X87
     status() << "Begin test of floating-point environment." << std::flush;
 
     warning()
@@ -1079,6 +1080,9 @@ void 
Skeleton::UponTestFloatingPointEnvironment(wxCommandEvent&)
     LMI_ASSERT(fenv_is_valid());
 
     status() << "End test of floating-point environment." << std::flush;
+#else  // !defined LMI_X87
+    warning() << "This test does nothing at present." << std::flush;
+#endif // !defined LMI_X87
 }
 
 /// Test custom handler UponPaste().



reply via email to

[Prev in Thread] Current Thread [Next in Thread]