lmi
[Top][All Lists]
Advanced

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

Re: [lmi] (unsigned long long int)(float)(ULLONG_MAX-2)


From: Greg Chicares
Subject: Re: [lmi] (unsigned long long int)(float)(ULLONG_MAX-2)
Date: Mon, 17 Apr 2017 18:14:34 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.6.0

[historical documentation]

On 2017-03-24 14:25, Greg Chicares wrote:
[...Cacciola's documentation of his boost::numeric_cast implementation...]
> http://boost.cowic.de/rc/pdf/conversion.pdf page 14:
> 
> ToZero     (s >  S(LowestT)-S(1)  ) && (s <  S(HighestT)+S(1)  )
> ToNearest  (s >= S(LowestT)-S(0.5)) && (s <  S(HighestT)+S(0.5))
> ToInf      (s >  S(LowestT)-S(1)  ) && (s <= S(HighestT)       )
> ToNegInf   (s >= S(LowestT)       ) && (s <  S(HighestT)+S(1)  )
[...]
> Looking into the source again, for the Trunc policy which seems to be
> the applicable default (above), we have std::round_toward_zero as the
> default rounding style. Then, from the table above, the criterion for
> rejection (throwing) is:
> 
> ToZero     s <= S(lowest()) - S(1.0) || s >= S(highest()) + S(1.0)

I'm about to discard an old experimental version of 'bourn_cast.hpp',
but before throwing it away I wanted to post a diff here to record
that I had tested every combination of
  - increasing the magnitude of the integral limit by {0 vs. 1}
  - performing the comparison with {< and > vs. <= and >=}
in my earlier exploration of the boost method. It turns out that the
problem with the boost code, when converting long long int to float,
is that ULLONG_MIN is 2^64 exactly, while ULLONG_MAX is 2^64 - 1
(assuming two's complement), but the usual arithmetic conversions
turn both those numbers into floats equal to an exact integral power
of 2, so
 - "value >= 2^64" correctly rejects 2^64 (it exceeds ULLONG_MAX), but
 - "value <= 2^64" incorrectly rejects ULLONG_MIN

---------8<--------8<--------8<--------8<--------8<--------8<--------8<-------
diff --git a/bourn_cast.hpp b/bourn_cast.hpp
index 2d5d02f..384c58d 100644
--- a/bourn_cast.hpp
+++ b/bourn_cast.hpp
@@ -168,9 +168,16 @@ inline To bourn_cast(From from, std::true_type, 
std::false_type)
 
     if(std::isnan(from))
         throw std::runtime_error("Cannot cast NaN to integral.");
-    if(from < to_traits::lowest())
+// This would be right according to Cacciola's analysis:
+//      if(from <= From(to_traits::lowest()) - From(1)) // wrong
+//      if(from <= From(to_traits::lowest()))           // wrong
+//      if(from < From(to_traits::lowest()) - From(1))  // wrong
+    if(from < From(to_traits::lowest()))                // correct
         throw std::runtime_error("Cast would transgress lower limit.");
-    if(adj_max <= from)
+//      if(From(to_traits::max())           < from)  // wrong
+//      if(From(to_traits::max()) + From(1) < from)  // wrong
+//      if(From(to_traits::max())           <= from) // wrong
+    if(adj_max <= from)                              // correct
         throw std::runtime_error("Cast would transgress upper limit.");
     To const r = static_cast<To>(from);
     if(r != from)
--------->8-------->8-------->8-------->8-------->8-------->8-------->8-------




reply via email to

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