lmi-commits
[Top][All Lists]
Advanced

[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.



reply via email to

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