
Hi again, The problem: For some Integral Constants values mpl::divides<A.,B> truncates. The solution: A new operator... mpl::rational_divides<A,B> When it is desired not to truncate, this form will preserve the fractional part by if necessary converting to a rational number. With this operator in place it is also possible to 'reduce' rationals to integers where possible and further to keep integral constants as integral types by default, knowing that conversion will be automatic if a fraction is required to prevent loss of precision. No mpl::divides<A.,B> is available if A or B is a rational types, because it is assumed that if you are using rationals you require the fraction preserving behaviour. A numeric_cast to an integral type can be used to solve this where necessary. Errors of using divides<A,B> on rationals will show at compile time. Thanks to Alexey Gurtovoy for the conversion mechanism As an example: int main() { // current division operator typedef boost::mpl::divides< boost::mpl::int_<2>, boost::mpl::int_<3> >::type int_div; // error no mpl::divides allowed for rationals /* typedef boost::mpl::divides< boost::mpl::rational_c<int,2>, boost::mpl::rational_c<int,3> >::type XXX;*/ // when some type might be a rational and rational behaviour rather than truncation is required: typedef boost::mpl::rational_divides< boost::mpl::rational_c<long,2>, boost::mpl::int_<3> >::type rat_div1; //also works on int_'s etc... typedef boost::mpl::rational_divides< boost::mpl::int_<2>, boost::mpl::int_<3> >::type rat_div2; typedef boost::mpl::rational_divides< boost::mpl::rational_int<2>, boost::mpl::rational_int<3> >::type rat_div3; // also 'promotes' to int_ where possible typedef boost::mpl::rational_divides< boost::mpl::rational_int<210>, boost::mpl::rational_int<3> >::type rat_div4; // also 'promotes' to int_ where possible typedef boost::mpl::rational_divides< boost::mpl::int_<210>, boost::mpl::integral_c<long,3> >::type rat_div5; std::ofstream os("output.txt"); os << typeid(int_div).name() <<'\n'; os << typeid(rat_div1).name() <<'\n'; os << typeid(rat_div2).name() <<'\n'; os << typeid(rat_div3).name() <<'\n'; os << typeid(rat_div4).name() <<'\n'; os << typeid(rat_div5).name() <<'\n'; } output: (VC7.1) struct boost::mpl::integral_c<int,0> struct boost::mpl::rational_c<long,2,3> struct boost::mpl::rational_c<int,2,3> struct boost::mpl::rational_c<int,2,3> struct boost::mpl::int_<70> struct boost::mpl::long_<70> regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> wrote With this operator in place it is also possible
to 'reduce' rationals to integers where possible and further to keep integral constants as integral types by default, knowing that conversion will be automatic if a fraction is required to prevent loss of precision.
To automatically 'reduce' a rational_c to an integral_c where its denominator is 1 was not sound. In practise the two types are not equivalent due to their different behaviour in division. Obvious really. The obvious and safe scheme involves using the mpl::operator::divides and always 'promoting' to a rational_c in any mixed arithmetic. regards Andy Little

Andy Little writes:
The problem: For some Integral Constants values mpl::divides<A.,B> truncates.
Yep. Note that it's no different than int divides( int A, int B ) { return A / B; }
The solution: A new operator... mpl::rational_divides<A,B> When it is desired not to truncate, this form will preserve the fractional part by if necessary converting to a rational number. With this operator in place it is also possible to 'reduce' rationals to integers where possible and further to keep integral constants as integral types by default, knowing that conversion will be automatic if a fraction is required to prevent loss of precision.
Could you provide a specific use case where the above would be preferable over something like mpl::divide< to_rational<A>,B > ?
No mpl::divides<A.,B> is available if A or B is a rational types, because it is assumed that if you are using rationals you require the fraction preserving behaviour.
I'd assume that 'divides' on rational types actually wouldn't truncate anything. Why one would prefer to have a separate metafunction for doing the right thing instead of simply overriding the standard one?
A numeric_cast to an integral type can be used to solve this where necessary.
Errors of using divides<A,B> on rationals will show at compile time.
Thanks to Alexey Gurtovoy for the conversion mechanism
You're welcome! -- Aleksey Gurtovoy MetaCommunications Engineering

"Aleksey Gurtovoy" <agurtovoy@meta-comm.com> wrote
Andy Little writes:
The solution: A new operator... mpl::rational_divides<A,B> When it is desired not to truncate, this form will preserve the fractional part by if necessary converting to a rational number. With this operator in place it is also possible to 'reduce' rationals to integers where possible and further to keep integral constants as integral types by default, knowing that conversion will be automatic if a fraction is required to prevent loss of precision.
Could you provide a specific use case where the above would be preferable over something like
mpl::divide< to_rational<A>,B >
?
That seems like a good solution. :-) though rational_divides<A,B> is slightly less typing.
Why one would prefer to have a separate metafunction for doing the right thing instead of simply overriding the standard one?
Is 1/2 == 0 'the right thing'? Integer division is one operation where a silent loss of information occurs with no warning. I think I would prefer divides<int_<1>,int_<2> > to return a rational<1,2>. (which incidentally would seamlessly integrate rationals and integers and allow the automatic reduction) . However to preserve the status-quo, a new function name could be used where non-truncating behaviour is required irrespective of type; as well as a quotient_of_divides which always truncates, a careful_divides function which verifies that no truncation has occurred, etc. The original reason for wanting this behaviour was in exponents for dimensional analysis. Rationals are required to cover rare cases. As well as some presumed effect on compilation time, the other effect of using rationals over integers is to lengthen the signature of the Dimension type, which affects legibility of error messages, just for the sake of these few rare cases. This was the rationale behind automatically 'reducing' rationals to integral types where possible, thus easing use of integrals in definitions of Dimension types, however the knock on effect was that division on two 'reduced' rationals would simply be division on two integral types( with quiet truncation). Hence the name change. FWIW the automatic reduction of rational to integral was problematic due to the above issues. The idea of 'reducing' rationals to integer types where possible is still attractive, but making the cast explicit eg via a to_integral_if_possible<T> function. regards Andy Little
participants (2)
-
Aleksey Gurtovoy
-
Andy Little