[math] potentian bug: iround throws, given double( numeric_limits<int>::min() )

Hello, The docs of the Rounding Functions say: If the argument v is either non-finite or else outside the range of the result type, then returns the result of rounding_error: by default this throws an instance of boost::math::rounding_error. So the example shown below seems to show a bug, since std::numeric_limits<int>::min() is *not* outside the range of int. Or did I miss something? <code> #include <boost/math/special_functions/round.hpp> #include <cassert> #include <limits> int main() { int const i = std::numeric_limits<int>::min(); double const x = i; assert( i == boost::math::iround(x) ); } </code> Regards Kris

The docs of the Rounding Functions say:
If the argument v is either non-finite or else outside the range of the result type, then returns the result of rounding_error: by default this throws an instance of boost::math::rounding_error.
So the example shown below seems to show a bug, since std::numeric_limits<int>::min() is *not* outside the range of int. Or did I miss something?
It's a bug: the error checking is off by one for negative values. Fixed in Trunk. Thanks, John.

Al, I tried compiling and executing this code simply to understand the issues. The compilation been successful but while executing I get below errors - ----- $ ./test-3.exe terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost: :exception_detail::error_info_injector<boost::math::rounding_error> >' what(): Error in function boost::math::iround<d>(d): Value -2147483648 can not be represented in the target integer type. Aborted (core dumped) $ ----- Above was did tried on Cygwin platform (1.7.9(0.237/5/3) 2011-03-29 10:10 i686 Cygwin). And on Ubuntu, I have same error message while executing - ----- ./test-1 terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::math::rounding_error>
' what(): Error in function boost::math::iround<d>(d): Value -2147483648 can not be represented in the target integer type. Aborted
----- ~ BR ----- On Wed, Oct 12, 2011 at 4:38 PM, John Maddock <boost.regex@virgin.net>wrote:
The docs of the Rounding Functions say:
If the argument v is either non-finite or else outside the range of the result type, then returns the result of rounding_error: by default this throws an instance of boost::math::rounding_error.
So the example shown below seems to show a bug, since std::numeric_limits<int>::min(**) is *not* outside the range of int. Or did I miss something?
It's a bug: the error checking is off by one for negative values.
Fixed in Trunk.
Thanks, John.
______________________________**_________________ Unsubscribe & other changes: http://lists.boost.org/** mailman/listinfo.cgi/boost<http://lists.boost.org/mailman/listinfo.cgi/boost>

I tried compiling and executing this code simply to understand the issues. The compilation been successful but while executing I get below errors -
Correct, that's the bug manifesting itself. It should be fixed in Trunk and Release branches though (works for me)? John.

2011/10/12 John Maddock <boost.regex@virgin.net>
The docs of the Rounding Functions say:
If the argument v is either non-finite or else outside the range of the result type, then returns the result of rounding_error: by default this throws an instance of boost::math::rounding_error.
So the example shown below seems to show a bug, since std::numeric_limits<int>::min(**) is *not* outside the range of int. Or did I miss something?
It's a bug: the error checking is off by one for negative values.
Fixed in Trunk.
Thanks, John.
A thought came to my mind... Theoretically, is it possible for the following conditions to be true? static_cast<float>( std::numeric_limits<int>::min() ) < std::numeric_limits<int>::min() static_cast<double>( std::numeric_limits<int>::min() ) < std::numeric_limits<int>::min() static_cast<long double>( std::numeric_limits<int>::min() ) < std::numeric_limits<int>::min() static_cast<float>( std::numeric_limits<int>::max() ) > std::numeric_limits<int>::max() static_cast<double>( std::numeric_limits<int>::max() ) > std::numeric_limits<int>::max() static_cast<long double>( std::numeric_limits<int>::max() ) > std::numeric_limits<int>::max() After all, casting to floating-point may loose precision... I have no knowledge in this area, so it may be just a silly thought. Regards Kris

A thought came to my mind... Theoretically, is it possible for the following conditions to be true? static_cast<float>( std::numeric_limits<int>::min() ) < std::numeric_limits<int>::min() static_cast<double>( std::numeric_limits<int>::min() ) < std::numeric_limits<int>::min() static_cast<long double>( std::numeric_limits<int>::min() ) < std::numeric_limits<int>::min() static_cast<float>( std::numeric_limits<int>::max() ) > std::numeric_limits<int>::max() static_cast<double>( std::numeric_limits<int>::max() ) > std::numeric_limits<int>::max() static_cast<long double>( std::numeric_limits<int>::max() ) > std::numeric_limits<int>::max() After all, casting to floating-point may loose precision... I have no knowledge in this area, so it may be just a silly thought.
Ah, yes: when I fixed this bug I had to disable some of new the tests for type float because of that very issue: an integer type converted to type float may actually be outside the range of an integer due to rounding during the conversion. John.

2011/10/20 John Maddock <boost.regex@virgin.net>
A thought came to my mind... Theoretically, is it possible for the
following conditions to be true? static_cast<float>( std::numeric_limits<int>::min(**) ) < std::numeric_limits<int>::min(**) static_cast<double>( std::numeric_limits<int>::min(**) ) < std::numeric_limits<int>::min(**) static_cast<long double>( std::numeric_limits<int>::min(**) ) < std::numeric_limits<int>::min(**) static_cast<float>( std::numeric_limits<int>::max(**) ) > std::numeric_limits<int>::max(**) static_cast<double>( std::numeric_limits<int>::max(**) ) > std::numeric_limits<int>::max(**) static_cast<long double>( std::numeric_limits<int>::max(**) ) > std::numeric_limits<int>::max(**) After all, casting to floating-point may loose precision... I have no knowledge in this area, so it may be just a silly thought.
Ah, yes: when I fixed this bug I had to disable some of new the tests for type float because of that very issue: an integer type converted to type float may actually be outside the range of an integer due to rounding during the conversion.
John.
Ah, thanks for a confirmation... I am interested in a resolution here, which I would like to implement in a function I wrote as a more general iround; I call it round_cast(): <code> template < class R, class T, class Policy > inline R round_cast( T const& x, Policy const& pol ) { BOOST_MATH_STD_USING T r = boost::math::round(x,pol); if( r > boost::integer_traits<R>::const_max || r < boost::integer_traits<R>::const_min ) return static_cast<R>( boost::math::policies::raise_rounding_error( "cz::ar::round_cast<target_type,%1%>(%1%)", 0, x, pol ) ); return static_cast<R>(r); } template < class R, class T > inline R round_cast( T const& x ) { return round_cast<R>( x, boost::math::policies::policy<>() ); } </code> Regards Kris

Ah, thanks for a confirmation...
I am interested in a resolution here, which I would like to implement in a function I wrote as a more general iround; I call it round_cast():
<code> template < class R, class T, class Policy > inline R round_cast( T const& x, Policy const& pol ) { BOOST_MATH_STD_USING T r = boost::math::round(x,pol); if( r > boost::integer_traits<R>::const_max || r < boost::integer_traits<R>::const_min ) return static_cast<R>( boost::math::policies::raise_rounding_error( "cz::ar::round_cast<target_type,%1%>(%1%)", 0, x, pol ) ); return static_cast<R>(r); }
template < class R, class T > inline R round_cast( T const& x ) { return round_cast<R>( x, boost::math::policies::policy<>() ); } </code>
Isn't that more or less the same as: http://www.boost.org/doc/libs/1_47_0/libs/numeric/conversion/doc/html/boost_... John.

2011/10/20 John Maddock <boost.regex@virgin.net>
Ah, thanks for a confirmation...
I am interested in a resolution here, which I would like to implement in a function I wrote as a more general iround; I call it round_cast():
<code> template < class R, class T, class Policy > inline R round_cast( T const& x, Policy const& pol ) { BOOST_MATH_STD_USING T r = boost::math::round(x,pol); if( r > boost::integer_traits<R>::**const_max || r < boost::integer_traits<R>::**const_min ) return static_cast<R>( boost::math::policies::raise_** rounding_error( "cz::ar::round_cast<target_**type,%1%>(%1%)", 0, x, pol ) ); return static_cast<R>(r); }
template < class R, class T > inline R round_cast( T const& x ) { return round_cast<R>( x, boost::math::policies::policy<**>() ); } </code>
Isn't that more or less the same as: http://www.boost.org/doc/libs/** 1_47_0/libs/numeric/**conversion/doc/html/boost_** numericconversion/improved_**numeric_cast__.html<http://www.boost.org/doc/libs/1_47_0/libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html>
John.
I thought that was only for checking range. Or do you mean round(), and then numeric_cast<>() instead of checking range manually in round_cast<>()? Regards Kris

2011/10/20 Krzysztof Czainski <1czajnik@gmail.com>
Isn't that more or less the same as: http://www.boost.org/doc/libs/**
1_47_0/libs/numeric/**conversion/doc/html/boost_** numericconversion/improved_**numeric_cast__.html<http://www.boost.org/doc/libs/1_47_0/libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html>
John.
I thought that was only for checking range. Or do you mean round(), and then numeric_cast<>() instead of checking range manually in round_cast<>()?
Ah, that can be customized with a policy, but the only rounding (not Floor/Ceil/Trunc) policy provided is RoundEven which doesn't do exactly what I want, while math::round does ;) Besides, with math::round() I can use the same policy I use for other math functions. Regards, Kris

I thought that was only for checking range. Or do you mean round(), and then numeric_cast<>() instead of checking range manually in round_cast<>()?
Ah, that can be customized with a policy, but the only rounding (not Floor/Ceil/Trunc) policy provided is RoundEven which doesn't do exactly what I want, while math::round does ;)
Besides, with math::round() I can use the same policy I use for other math functions.
Nod. I guess the functions could something like: template <class R, class T> R round_to(const T&); template <class R, class T> R trunc_to(const T&); which would provide generic versions of iround/itrunc (although R need not be an integer type, as long as there's a static_cast from T to R). I'm not particularly sold on those names though, I guess "round_cast/trunc_cast" would be an alternative. John.

2011/10/21 John Maddock <boost.regex@virgin.net>
template <class R, class T> R round_to(const T&);
template <class R, class T> R trunc_to(const T&);
which would provide generic versions of iround/itrunc (although R need not be an integer type, as long as there's a static_cast from T to R).
I'm not particularly sold on those names though, I guess "round_cast/trunc_cast" would be an alternative.
John.
Personally, I prefer names "round_cast/trunc_cast", as they better describe what's being done. I already use a function "round_to", that does something else: template < class T > T round_to( const T& x, const T& order ) { return round( x / order ) * order; // By the way, can this be achieved more efficiently? } I'm not sure if "round_to" is the best name for this, but I think it is not the right name for "round_cast" ;-) Regards, Kris

Personally, I prefer names "round_cast/trunc_cast", as they better describe what's being done. I already use a function "round_to", that does something else:
template < class T > T round_to( const T& x, const T& order ) { return round( x / order ) * order; // By the way, can this be achieved more efficiently? }
I'm not sure if "round_to" is the best name for this, but I think it is not the right name for "round_cast" ;-)
OK, can you file a feature request at svn.boost.org so I don't forget this? Thanks, John.

2011/10/22 John Maddock <boost.regex@virgin.net>
OK, can you file a feature request at svn.boost.org so I don't forget this?
Thanks, John.
Done, Ticket #6047 - about round_cast(). Would you like a ticket for the following round_to as well? template < class T > T round_to( const T& x, const T& order ) { return round( x / order ) * order; } I'm still not sure if: can r > boost::integer_traits<R>::const_max be true, and still static_cast<R>(r) == boost::integer_traits<R>::const_max? Regards, Kris

OK, can you file a feature request at svn.boost.org so I don't forget this?
Thanks, John.
Done, Ticket #6047 - about round_cast().
Would you like a ticket for the following round_to as well? template < class T > T round_to( const T& x, const T& order ) { return round( x / order ) * order; }
I'm not sure about that one, if "order" is anything other than a power of T's radix then the result will be rounded - ie the result will not necessarily actually be a true multiple of "order"?
I'm still not sure if: can r > boost::integer_traits<R>::const_max be true, and still static_cast<R>(r) == boost::integer_traits<R>::const_max?
Good question, I believe that can be the case if *r has not been rounded*, for example if r == boost::integer_traits<R>::const_max + 0.1. HTH, John.

[Krzysztof Czaiński]
Would you like a ticket for the following round_to as well?
template < class T > T round_to( const T& x, const T& order ) { return round( x / order ) * order; }
[John Maddock]
I'm not sure about that one, if "order" is anything other than a power of T's radix then the result will be rounded - ie the result will not necessarily actually be a true multiple of "order"?
Do you mean the loss of precision when doing "x/order" and then "<result>*order" ? Anyway, I am not really convinced myself whether this round_to() is a good candidate for adding to boost ;-) I just wasn't sure if you were asking for a ticket with that as well. However, my aside question remains, can that be implemented better? [Krzysztof Czaiński]
I'm still not sure if: can r > boost::integer_traits<R>::**const_max be
true, and still static_cast<R>(r) == boost::integer_traits<R>::**const_max?
[John Maddock]
Good question, I believe that can be the case if *r has not been rounded*, for example if r == boost::integer_traits<R>::**const_max + 0.1.
What I meant above, and should have written, is that "T r = round(x)", where x is the input value of a floating-point type T. With this assumption, do the conditions still hold, or can there be some roundidg error messing with them? Regards Kris

Do you mean the loss of precision when doing "x/order" and then "<result>*order" ? Anyway, I am not really convinced myself whether this round_to() is a good candidate for adding to boost ;-) I just wasn't sure if you were asking for a ticket with that as well.
However, my aside question remains, can that be implemented better?
Not sure to be honest.
Good question, I believe that can be the case if *r has not been rounded*, for example if r == boost::integer_traits<R>::**const_max + 0.1.
What I meant above, and should have written, is that "T r = round(x)", where x is the input value of a floating-point type T. With this assumption, do the conditions still hold, or can there be some roundidg error messing with them?
Also not sure, it may certainly be true that: int i = boost::integer_traits<R>::const_min; float f = i; assert(f < i); // succeeds!! assert(i == f); // fails Not sure what happens when you convert back though, John.
participants (3)
-
John Maddock
-
Krzysztof Czainski
-
Mukkaysh Srivastav