[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master da7e969 4/5: Add an enum whose enumerators ar
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master da7e969 4/5: Add an enum whose enumerators are suitable arguments for fesetround() |
Date: |
Thu, 29 Dec 2016 00:19:51 +0000 (UTC) |
branch: master
commit da7e969c5502c7bb1bd9b7626d05db31fa97592a
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Add an enum whose enumerators are suitable arguments for fesetround()
Define an enum to represent C++11 rounding control, with enumerators
matching the names, type, and values of the macros defined in <cfenv>,
so that it is thus compatible with std::fe[gs]etround().
Likewise, define an enum to represent IEEE 754 precision control, with
enumerators matching the names, type, and values of the macros proposed
by WG14 N751/J11 if they are defined, or otherwise matching the names
proposed by WG14 N751/J11 and the values used by glibc.
In mapping these enums to macros, certain assumptions are made. Header
<cfenv> is included, and is assumed to define the four rounding-control
macros unconditionally, although the standard seems to guarantee that
only if the implementation provides working fe[gs]etround() functions.
All rounding macros are assumed to correspond to values representable
as decltype(FE_TONEAREST); likewise, decltype(FE_FLTPREC) is assumed to
be appropriate for all precision macros iff FE_FLTPREC is defined.
Rename various identifiers. The x87 control word parameters (e.g., the
precision-control values) used by msvc are specific to msvc, not to msw;
those used by x87 hardware are specific to the x87, not to IEEE 754.
---
fenv_lmi.cpp | 34 +++++++++++++++--
fenv_lmi.hpp | 25 +++++++++++++
fenv_lmi_test.cpp | 30 +++++++--------
fenv_lmi_x86.hpp | 105 ++++++++++++++++++++++++++++-------------------------
4 files changed, 126 insertions(+), 68 deletions(-)
diff --git a/fenv_lmi.cpp b/fenv_lmi.cpp
index 60b995c..3831db5 100644
--- a/fenv_lmi.cpp
+++ b/fenv_lmi.cpp
@@ -88,7 +88,13 @@ e_ieee754_precision fenv_precision()
: throw std::runtime_error("Failed to determine hardware precision.")
;
#elif defined LMI_X86
- return intel_control_word(x87_control_word()).pc();;
+ e_x87_precision pc = intel_control_word(x87_control_word()).pc();
+ return
+ (x87_fe_fltprec == pc) ? fe_fltprec
+ : (x87_fe_dblprec == pc) ? fe_dblprec
+ : (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.
@@ -105,8 +111,14 @@ void fenv_precision(e_ieee754_precision precision_mode)
;
_control87(z, MCW_PC);
#elif defined LMI_X86
+ e_x87_precision pc =
+ (fe_fltprec == precision_mode) ? x87_fe_fltprec
+ : (fe_dblprec == precision_mode) ? x87_fe_dblprec
+ : (fe_ldblprec == precision_mode) ? x87_fe_ldblprec
+ : throw std::runtime_error("Failed to set hardware precision.")
+ ;
intel_control_word control_word(x87_control_word());
- control_word.pc(precision_mode);
+ control_word.pc(pc);
x87_control_word(control_word.cw());
#else // Unknown compiler or platform.
# error Unknown compiler or platform.
@@ -134,7 +146,14 @@ e_ieee754_rounding fenv_rounding()
: throw std::runtime_error("Failed to determine rounding mode.")
;
#elif defined LMI_X86
- return intel_control_word(x87_control_word()).rc();;
+ e_x87_rounding rc = intel_control_word(x87_control_word()).rc();
+ return
+ (x87_fe_tonearest == rc) ? fe_tonearest
+ : (x87_fe_downward == rc) ? fe_downward
+ : (x87_fe_upward == rc) ? fe_upward
+ : (x87_fe_towardzero == rc) ? 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.
@@ -161,8 +180,15 @@ void fenv_rounding(e_ieee754_rounding rounding_mode)
;
_control87(z, MCW_RC);
#elif defined LMI_X86
+ e_x87_rounding rc =
+ (fe_tonearest == rounding_mode) ? x87_fe_tonearest
+ : (fe_downward == rounding_mode) ? x87_fe_downward
+ : (fe_upward == rounding_mode) ? x87_fe_upward
+ : (fe_towardzero == rounding_mode) ? x87_fe_towardzero
+ : throw std::runtime_error("Failed to set rounding mode.")
+ ;
intel_control_word control_word(x87_control_word());
- control_word.rc(rounding_mode);
+ control_word.rc(rc);
x87_control_word(control_word.cw());
#else // Unknown compiler or platform.
# error Unknown compiler or platform.
diff --git a/fenv_lmi.hpp b/fenv_lmi.hpp
index 32b9929..ac7a3bd 100644
--- a/fenv_lmi.hpp
+++ b/fenv_lmi.hpp
@@ -50,6 +50,8 @@
# endif // Pragma STDC FENV_ACCESS implemented.
#endif // defined LMI_IEC_559
+#include <cfenv>
+
/// These functions manage the floating-point environment.
///
/// void fenv_initialize();
@@ -89,6 +91,29 @@
namespace floating_point_environment {} // doxygen workaround.
+#if defined FE_DBLPREC
+enum e_ieee754_precision : decltype(FE_FLTPREC)
+ {fe_fltprec = FE_FLTPREC
+ ,fe_dblprec = FE_DBLPREC
+ ,fe_ldblprec = FE_LDBLPREC
+ };
+#else // !defined FE_DBLPREC
+// If not otherwise defined, use glibc's values.
+enum e_ieee754_precision
+ {fe_fltprec = 0x0000
+ ,fe_dblprec = 0x0200
+ ,fe_ldblprec = 0x0300
+ };
+#endif // !defined FE_DBLPREC
+
+// Assume <cfenv> defines these macros.
+enum e_ieee754_rounding : decltype(FE_TONEAREST)
+ {fe_tonearest = FE_TONEAREST
+ ,fe_downward = FE_DOWNWARD
+ ,fe_upward = FE_UPWARD
+ ,fe_towardzero = FE_TOWARDZERO
+ };
+
enum enum_fenv_indulgence
{e_fenv_indulge_nothing = 0
,e_fenv_indulge_0x027f = 0x027f
diff --git a/fenv_lmi_test.cpp b/fenv_lmi_test.cpp
index bc4e43a..f4454e1 100644
--- a/fenv_lmi_test.cpp
+++ b/fenv_lmi_test.cpp
@@ -70,20 +70,20 @@ int test_main(int, char*[])
#if defined LMI_X86
unsigned short int cw = 0x0000;
- BOOST_TEST_EQUAL_BITS(0x037f, msw_to_intel(0x0008001f));
+ BOOST_TEST_EQUAL_BITS(0x037f, msvc_to_intel(0x0008001f));
- BOOST_TEST_EQUAL_BITS(0x0008001f, intel_to_msw(0x037f));
+ BOOST_TEST_EQUAL_BITS(0x0008001f, intel_to_msvc(0x037f));
cw = 0x037f;
- BOOST_TEST_EQUAL_BITS(0x0008001f, intel_to_msw(cw));
- BOOST_TEST_EQUAL_BITS(cw, msw_to_intel(0x0008001f));
- BOOST_TEST_EQUAL_BITS(cw, msw_to_intel(intel_to_msw(cw)));
+ BOOST_TEST_EQUAL_BITS(0x0008001f, intel_to_msvc(cw));
+ BOOST_TEST_EQUAL_BITS(cw, msvc_to_intel(0x0008001f));
+ BOOST_TEST_EQUAL_BITS(cw, msvc_to_intel(intel_to_msvc(cw)));
cw = 0x027f;
- BOOST_TEST_EQUAL_BITS(cw, msw_to_intel(intel_to_msw(cw)));
+ BOOST_TEST_EQUAL_BITS(cw, msvc_to_intel(intel_to_msvc(cw)));
cw = 0x037f;
- BOOST_TEST_EQUAL_BITS(cw, msw_to_intel(intel_to_msw(cw)));
+ BOOST_TEST_EQUAL_BITS(cw, msvc_to_intel(intel_to_msvc(cw)));
// Most reserved bits should be left as initialized by FINIT...
x87_control_word(0x0000);
@@ -105,21 +105,21 @@ int test_main(int, char*[])
// traps this upon conversion between different control-word
// types, but not otherwise--it guards against accidental misuse,
// not fraud such as:
- // e_ieee754_precision(0x01); // Poor practice at best.
- // e_msw_pc (0x03); // Unspecified behavior: C++98 7.2/9 .
+ // e_x87_precision (0x01); // Poor practice at best.
+ // e_msvc_precision(0x03); // Unspecified behavior: C++98 7.2/9 .
intel_control_word invalid_intel_control_word(0);
- invalid_intel_control_word.pc(e_ieee754_precision(0x01));
+ invalid_intel_control_word.pc(e_x87_precision (0x01));
BOOST_TEST_THROW
- (msw_control_word msw_error (invalid_intel_control_word)
+ (msvc_control_word msvc_error (invalid_intel_control_word)
,std::logic_error
,"Invalid fpu PC value."
);
- msw_control_word invalid_msw_control_word (0);
- invalid_msw_control_word.pc (e_msw_pc (0x03));
+ msvc_control_word invalid_msvc_control_word (0);
+ invalid_msvc_control_word.pc (e_msvc_precision(0x03));
BOOST_TEST_THROW
- (intel_control_word intel_error(invalid_msw_control_word )
+ (intel_control_word intel_error(invalid_msvc_control_word )
,std::logic_error
,"Invalid fpu PC value."
);
@@ -149,7 +149,7 @@ int test_main(int, char*[])
# endif // defined __MINGW32__
# if defined _MCW_EM
- // Test the ms C rtl method.
+ // Test the msvc rtl method.
x87_control_word(0x0000);
_control87(_MCW_EM, _MCW_EM);
_control87(_RC_NEAR, _MCW_RC);
diff --git a/fenv_lmi_x86.hpp b/fenv_lmi_x86.hpp
index a30389a..19764e7 100644
--- a/fenv_lmi_x86.hpp
+++ b/fenv_lmi_x86.hpp
@@ -32,7 +32,7 @@
#endif // defined __BORLANDC__ || defined _MSC_VER
#if defined LMI_X86
-/// These functions manipulate the x86 fpu (80x87) control word. This
+/// 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:
/// 1980: 8087 introduced
@@ -40,7 +40,7 @@
/// 1999: C finally gets fesetenv(), but without precision control *
/// which left setting the control word to nonstandard routines or
/// nonportable asm, and part is that function _control87() in the
-/// widely-used ms C rtl takes an argument that differs gratuitously
+/// widely-used msvc rtl takes an argument that differs gratuitously
/// from the hardware control word--see, e.g.:
/// http://groups.google.com/groups?selm=34775BB8.E10BA020%40tc.umn.edu
///
@@ -86,9 +86,9 @@ struct intel_control_word_for_exposition_only
unsigned int :4; // Bits 12-15.
};
-/// The ms C rtl control word, represented as bitfields.
+/// The msvc rtl control word, represented as bitfields.
-struct msw_control_word_for_exposition_only
+struct msvc_control_word_for_exposition_only
{
unsigned int PM:1; // Bit 0.
unsigned int UM:1; // Bit 1.
@@ -104,36 +104,43 @@ struct msw_control_word_for_exposition_only
unsigned int :12; // Bits 20-31: reserved.
};
-/// Precision-control values used by 80x87 hardware. The enumerators
-/// are lowercase versions of the GNU/Linux <fenvwm.h> macros,
-/// although the constant-expressions may differ.
+/// IEEE 754 precision-control values used by x87 hardware.
+///
+/// Cf. the cognate macros in WG14 N751/J11.
+///
+/// The enumerators are prefixed lowercase versions of those cognates,
+/// although the constant-expressions may differ in value and in type.
-enum e_ieee754_precision
- {fe_fltprec = 0x00
- ,fe_dblprec = 0x02
- ,fe_ldblprec = 0x03
+enum e_x87_precision
+ {x87_fe_fltprec = 0x00
+ ,x87_fe_dblprec = 0x02
+ ,x87_fe_ldblprec = 0x03
};
-/// Precision-control values used by ms C rtl, which differ
+/// Precision-control values used by msvc rtl, which differ
/// gratuitously from hardware values.
-enum e_msw_pc
- {msw_fltprec = 0x02
- ,msw_dblprec = 0x01
- ,msw_ldblprec = 0x00
+enum e_msvc_precision
+ {msvc_fltprec = 0x02
+ ,msvc_dblprec = 0x01
+ ,msvc_ldblprec = 0x00
};
-/// Rounding-control values. The enumerators are lowercase versions of
-/// the C99 7.6/7 macros, although the constant-expressions may differ.
-
-enum e_ieee754_rounding
- {fe_tonearest = 0x00
- ,fe_downward = 0x01
- ,fe_upward = 0x02
- ,fe_towardzero = 0x03
+/// IEEE 754 rounding-control values used by x87 hardware.
+///
+/// Cf. the cognate macros in C++11 <cfenv>.
+///
+/// The enumerators are prefixed lowercase versions of those cognates,
+/// although the constant-expressions may differ in value and in type.
+
+enum e_x87_rounding
+ {x87_fe_tonearest = 0x00
+ ,x87_fe_downward = 0x01
+ ,x87_fe_upward = 0x02
+ ,x87_fe_towardzero = 0x03
};
-/// Parameters of 80x87 hardware control word.
+/// Parameters of x87 hardware control word.
///
/// Reserved bits:
/// 'reserved_values' specifies values of reserved bits.
@@ -146,8 +153,8 @@ struct intel_control_word_parameters
{
typedef unsigned short int integer_type;
enum {nbits = 16};
- typedef e_ieee754_precision pc_type;
- typedef e_ieee754_rounding rc_type;
+ typedef e_x87_precision pc_type;
+ typedef e_x87_rounding rc_type;
enum {reserved_values = 0x0040};
enum {settable = 0x0f3f};
enum {im_bit = 0};
@@ -158,13 +165,13 @@ struct intel_control_word_parameters
enum {pm_bit = 5};
enum {pc_bit0 = 8};
enum {rc_bit0 = 10};
- static pc_type pc24() {return fe_fltprec ;}
- static pc_type pc53() {return fe_dblprec ;}
- static pc_type pc64() {return fe_ldblprec;}
+ static pc_type pc24() {return x87_fe_fltprec ;}
+ static pc_type pc53() {return x87_fe_dblprec ;}
+ static pc_type pc64() {return x87_fe_ldblprec;}
static pc_type pcerror() {throw std::logic_error("Invalid fpu PC value.");}
};
-/// Parameters of ms C rtl control word, which differ gratuitously
+/// Parameters of msvc rtl control word, which differ gratuitously
/// from hardware parameters.
///
/// 'settable' in terms of the ms macros is
@@ -174,12 +181,12 @@ struct intel_control_word_parameters
///
/// 'reserved_values' can have no meaning here, for ms documents none.
-struct msw_control_word_parameters
+struct msvc_control_word_parameters
{
typedef unsigned int integer_type;
enum {nbits = 32};
- typedef e_msw_pc pc_type;
- typedef e_ieee754_rounding rc_type;
+ typedef e_msvc_precision pc_type;
+ typedef e_x87_rounding rc_type;
enum {reserved_values = 0x0000};
enum {settable = 0x000b031f};
enum {im_bit = 4};
@@ -190,15 +197,15 @@ struct msw_control_word_parameters
enum {pm_bit = 0};
enum {pc_bit0 = 16};
enum {rc_bit0 = 8};
- static pc_type pc24() {return msw_fltprec ;}
- static pc_type pc53() {return msw_dblprec ;}
- static pc_type pc64() {return msw_ldblprec;}
+ static pc_type pc24() {return msvc_fltprec ;}
+ static pc_type pc53() {return msvc_dblprec ;}
+ static pc_type pc64() {return msvc_ldblprec;}
static pc_type pcerror() {throw std::logic_error("Invalid fpu PC value.");}
};
-/// Generic representation of 80x87 control word. The template
+/// Generic representation of x87 control word. The template
/// parameter selects between the hardware control word and the
-/// gratuitously-different one used by the ms C rtl.
+/// gratuitously-different one used by the msvc rtl.
template<typename ControlWordType>
class control_word
@@ -275,28 +282,28 @@ class control_word
};
typedef control_word<intel_control_word_parameters> intel_control_word;
-typedef control_word<msw_control_word_parameters> msw_control_word;
+typedef control_word<msvc_control_word_parameters> msvc_control_word;
// Conversion functions.
-inline unsigned int intel_to_msw(intel_control_word i)
+inline unsigned int intel_to_msvc(intel_control_word i)
{
- return msw_control_word(i).cw();
+ return msvc_control_word(i).cw();
}
-inline unsigned int intel_to_msw(unsigned short int i)
+inline unsigned int intel_to_msvc(unsigned short int i)
{
- return intel_to_msw(intel_control_word(i));
+ return intel_to_msvc(intel_control_word(i));
}
-inline unsigned short int msw_to_intel(msw_control_word m)
+inline unsigned short int msvc_to_intel(msvc_control_word m)
{
return intel_control_word(m).cw();
}
-inline unsigned short int msw_to_intel(unsigned int m)
+inline unsigned short int msvc_to_intel(unsigned int m)
{
- return msw_to_intel(msw_control_word(m));
+ return msvc_to_intel(msvc_control_word(m));
}
/// Default settings for x87 fpu.
@@ -317,7 +324,7 @@ inline unsigned short int x87_control_word()
control_word = static_cast<unsigned short int>(_control87(0, 0));
# elif defined _MSC_VER
// Test _MSC_VER last: some non-ms compilers or libraries define it.
- control_word = msw_to_intel(_control87(0, 0));
+ control_word = msvc_to_intel(_control87(0, 0));
# else // Unknown compiler or platform.
# error Unknown compiler or platform.
# endif // Unknown compiler or platform.
@@ -335,7 +342,7 @@ inline void x87_control_word(unsigned short int cw)
_control87(cw, 0x0ffff);
# elif defined _MSC_VER
// Test _MSC_VER last: some non-ms compilers or libraries define it.
- _control87(intel_to_msw(cw), 0x0ffffffff);
+ _control87(intel_to_msvc(cw), 0x0ffffffff);
# else // Unknown compiler or platform.
# error Unknown compiler or platform.
# endif // Unknown compiler or platform.