|
Boost : |
From: Bjorn Karlsson (bjorn.karlsson_at_[hidden])
Date: 2002-02-08 02:50:24
When looking at the numeric_cast implementation, I was perplexed at some of
the range checks.
For example, the test for too large value on a conversion from unsigned to
signed looks like this:
template <> struct greater_than_type_max<false, false> {
template <class X, class Y>
static inline bool check(X x, Y) {
return static_cast<X>(static_cast<Y>(x)) != x;
}
};
The implementation obviously expects values to wrap if too large, so for a
conversion to a smaller type, the first static_cast produces a smaller value
if the range was violated. Then, the value is cast back to the original
type, which would yield a different value than the original.
First of all, how safe is it to expect that all implementations wrap values?
(It's not specified by the Standard, but on the other hand I've never seen
any other behavior.)
Second, how could this ever work with types of the same size, say unsigned
integer and integer? Assuming that the unsigned integer has a value larger
than max for the integer, the first static_cast would produce a negative
value. The second static_cast would then wrap again and produce the original
value. What am I missing?
Onwards to a related question: What (if anything) should be done about the
following behavior?
When converting floating point types to integer types, the value is
truncated. In numeric_cast, the fraction isn't discarded until the return
(ie the range tests are performed with the original value). This can lead to
surprising behavior on edge values. Consider the following example:
char c;
double d=std::numeric_limits<char>::max();
d += .123456789123456;
c=d;
std::cout << "char value: " << (int)c << "\n";
try {
c=boost::numeric_cast<char>(d);
}
catch(boost::bad_numeric_cast& e) {
std::cout << e.what() << "\n";
}
The output on my system is:
char value: 127
bad numeric cast: loss of range in numeric_cast
The first output is correct, the second isn't.
Not very surprising - the check in numeric_cast in this case tests whether
127.123... is larger than 127, and I can't argue with the result :-).
However, it is not the behavior one would expect, so I'm thinking that it a)
deserves documentation or b) needs to be fixed. What do you think?
Bjorn Karlsson
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk