[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().
- [lmi-commits] [lmi] master updated (4cc9f66 -> 571924b), Greg Chicares, 2017/01/04
- [lmi-commits] [lmi] master ae3dc97 3/7: Test for x87, Greg Chicares, 2017/01/04
- [lmi-commits] [lmi] master 73e6bec 1/7: Do not indent top-level preprocessor directives, Greg Chicares, 2017/01/04
- [lmi-commits] [lmi] master ea356b1 4/7: Improve documentation, Greg Chicares, 2017/01/04
- [lmi-commits] [lmi] master 13090e1 2/7: Update reserved-name exceptions in coding rules, Greg Chicares, 2017/01/04
- [lmi-commits] [lmi] master 2c16778 5/7: Refactor to make ensuing changes simpler, Greg Chicares, 2017/01/04
- [lmi-commits] [lmi] master 571924b 7/7: Drop support for an ancient non-free compiler, Greg Chicares, 2017/01/04
- [lmi-commits] [lmi] master c07baf8 6/7: Conditionalize x87 code; provide <cfenv> alternatives where possible,
Greg Chicares <=