lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] master 204bd5f 5/5: Replace another assumption with


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 204bd5f 5/5: Replace another assumption with a static assertion
Date: Thu, 13 Apr 2017 06:58:29 -0400 (EDT)

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

    Replace another assumption with a static assertion
    
    Added a static assertion to address this issue that Vadim had raised:
    
      http://lists.nongnu.org/archive/html/lmi/2017-04/msg00001.html
    | Still, it does seem wrong to add 1 to the maximally representable
    | value of type "To" without being certain that it is _strictly_ less
    | than that of type "From".
---
 bourn_cast.hpp | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/bourn_cast.hpp b/bourn_cast.hpp
index d9c4b2d..039efa6 100644
--- a/bourn_cast.hpp
+++ b/bourn_cast.hpp
@@ -106,6 +106,33 @@ inline To bourn_cast(From from, std::false_type, 
std::true_type)
 /// Ones' complement might be handled thus [untested]:
 ///  - if(from < to_traits::lowest())
 ///  + if(from <= From(to_traits::lowest()) - 1)
+///
+/// Integral max() must be one less than an integer power of two,
+/// because C++11 [3.9.1/7] says "the representations of integral
+/// types shall define values by use of a pure binary numeration
+/// system", so the range of a signed eight-bit character (e.g.) is:
+///   [-127, +127] sign and magnitude, or ones' complement; or
+///   [-128, +127] two's complement;
+/// and the maximum must be 2^digits - 1 in any case.
+///
+/// It is not always feasible to compare the argument's value directly
+/// to this maximum in order to determine whether it is within range:
+/// see test_m64_neighborhood() in the accompanying unit test for a
+/// demonstration of the issues that arise in converting ULLONG_MAX to
+/// IEEE 754 binary32. Therefore, the tractable comparison
+///   argument <= maximum + 1  // i.e., <= 2^n exactly
+/// is substituted for the intractable
+///   argument < maximum       // < 0xFF... may exceed float precision
+/// To ensure that the addition 'maximum + 1' is not done in extended
+/// precision (as actually observed with various versions of gcc), it
+/// is performed through writes to volatile memory. To ensure that
+/// the maximum can be incremented, a static assertion compares the
+/// number of integral radix digits to the number of floating exponent
+/// digits. This assertion would be expected to fail with a 128-bit
+/// integral type and a 32-bit IEEE 754 float. It is written as a
+/// static assertion rather than a throw-statement because 128-bit
+/// long long integers are not generally available, so it is not
+/// possible to test such logic today.
 
 template<typename To, typename From>
 #if 201402L < __cplusplus
@@ -116,11 +143,8 @@ inline To bourn_cast(From from, std::true_type, 
std::false_type)
     using   to_traits = std::numeric_limits<To  >;
     using from_traits = std::numeric_limits<From>;
     static_assert(to_traits::is_integer && !from_traits::is_integer, "");
+    static_assert(to_traits::digits < from_traits::max_exponent, "");
 
-    // At least with i686-w64-mingw32-g++ version 4.9.1, this change:
-    // - if(From(to_traits::max()) + 1 <= from)
-    // + if(adj_max <= from)
-    // fixes incorrect results with '-O0'.
     static From const volatile raw_max = From(to_traits::max());
     static From const volatile adj_max = raw_max + From(1);
 



reply via email to

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