[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-------
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [lmi] (unsigned long long int)(float)(ULLONG_MAX-2),
Greg Chicares <=