----- Original Message -----
From: Bjorn Karlsson
To: 'Boost'
Sent: Friday, February 08, 2002 4:50 AM
Subject: [boost] numeric_cast - is this really right?

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

Hi.

I presented some time ago an improved implementation of numeric_cast<> which I believe solves the problems you mentioned.

I haven't submitted it for formal review yet because I still have to write its formal documentation, and I'm having very little time (I can read messages from this list and make short comments from time to time, but I'm too busy to sit down and write formal HTML documents right now).

However, the implementation and test bed are complete.

Although I do have to write the docs, the headers and test bed themselves are fully documented, so you won't have problems trying it.

This implementation uses some heavy metaprogramming in order to achieve maximum optimization. I did my best at writing the metaprogramming as portable as possible, but it could be the case the your compiler doesn't support it. In that case I'll be glad to fix it.

You can get it from

http://groups.yahoo.com/group/boost/files/improved_numeric_cast/numeric_cast.zip

Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com