[mpl::math Rational] type member

Hi Cromwell, in <boost/mpl/math/rational.hpp> In the definition for mpl::math::rational would it not be better to make the nested type member using the numerator and denominator rather than the input parameters.eg for: typedef rational<integral_c_<int,2>,integral_c<int,8> >::type type; currently type is a rational<integral_c_<int,2>,integral_c<int,8> > in the second case type is a rational<integral_c_<int,1>,integral_c<int,4> > I believe the second is superior. Can supply a patch if you like ... Secondly, are the next and prior members necessary? IMO they only make sense for integers. Thirdly, It should be noted that there is a <boost/mpl/math/rational_c.hpp> header, but as rational_c is defined in <boost/mpl/math/rational.hpp> I think its now both redundant and confusing. Cheers Andy Little

--- Andy Little wrote:
Hi Cromwell,
Hey, Andy.
in <boost/mpl/math/rational.hpp>
In the definition for mpl::math::rational would it not be better to make the nested type member using the numerator and denominator rather than the input parameters.eg for:
typedef rational<integral_c_<int,2>,integral_c<int,8>
::type type;
currently type is a
rational<integral_c_<int,2>,integral_c<int,8> >
Actually, the only thing BOOST_MPL_AUX_SELF_TYPEDEF(name) does is expand to typedef name type; or typedef struct name type; depending on whether a particular non-conforming compiler needs the second statement. No reliance on input parameters, AFAICT.
Secondly, are the next and prior members necessary? IMO they only make sense for integers.
They are provided for consistency with Boost::Rational, which implements increment and decrement operators.
Thirdly, It should be noted that there is a <boost/mpl/math/rational_c.hpp> header, but as rational_c is defined in <boost/mpl/math/rational.hpp> I think its now both redundant and confusing.
The first file was around long before I even took an interest in MPL. If and when MPL.Math is merged into Boost, we'll ask Aleksey to remove the old file. Cromwell D. Enage __________________________________ Yahoo! Mail - PC Magazine Editors' Choice 2005 http://mail.yahoo.com

"Cromwell Enage" wrote
Actually, the only thing BOOST_MPL_AUX_SELF_TYPEDEF(name) does is expand to
typedef name type;
or
typedef struct name type;
depending on whether a particular non-conforming compiler needs the second statement. No reliance on input parameters, AFAICT.
Yeah Right.................... ;-) 'name' which is "rational" in class template "rational" is an alias in class scope for 'name'<input_parameters>. What this is really about is potatoes and potatoes. So it is reliant on input parameters. I am arguing for a normalised version, so for my_rational<2,8>, my_rational<3,12> and my_rational<5,20> among others, the normalised version is my_rational<1,4> and thats what I think rational<...>::type should return.
Secondly, are the next and prior members necessary? IMO they only make sense for integers.
They are provided for consistency with Boost::Rational, which implements increment and decrement operators.
Just because rational does it doesnt mean its not daft... ;-) Does anybody **seriously** use that feature of Boost.Rational?
Thirdly, It should be noted that there is a <boost/mpl/math/rational_c.hpp> header, but as rational_c is defined in <boost/mpl/math/rational.hpp> I think its now both redundant and confusing.
The first file was around long before I even took an interest in MPL. If and when MPL.Math is merged into Boost, we'll ask Aleksey to remove the old file.
Mpl. Math seems to be getting quite popular.... ;-) cheers Andy little

--- Andy Little wrote:
'name' which is "rational" in class template "rational" is an alias in class scope for 'name'<input_parameters>. What this is really about is potatoes and potatoes. So it is reliant on input parameters.
Understood.
I am arguing for a normalised version, so for my_rational<2,8>, my_rational<3,12> and my_rational<5,20> among others, the normalised version is my_rational<1,4> and thats what I think rational<...>::type should return.
Okay. I'm not working on rational at the moment, so a patch would be appreciated.
Secondly, are the next and prior members necessary? IMO they only make sense for integers.
They are provided for consistency with Boost::Rational, which implements increment and decrement operators.
Just because rational does it doesnt mean its not daft... ;-) Does anybody **seriously** use that feature of Boost.Rational?
You can surround the offending typedefs with #ifdef BOOST_MPL_CFG_USE_MATH_RATIONAL_NEXT_PRIOR and #endif in your patch. Anyone that wants to use the typedefs can #define the macro themselves. Those of you who use boost::counting_iterator with Boost.Rational, we'd like to hear from you. Cromwell D. Enage __________________________________ Yahoo! FareChase: Search multiple travel sites in one click. http://farechase.yahoo.com

"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
I am arguing for a normalised version, so for my_rational<2,8>, my_rational<3,12> and my_rational<5,20> among others, the normalised version is my_rational<1,4> and thats what I think rational<...>::type should return.
Why should that normalization be done eagerly? I can see no good reason for it.
Secondly, are the next and prior members necessary? IMO they only make sense for integers.
They are provided for consistency with Boost::Rational, which implements increment and decrement operators.
Just because rational does it doesnt mean its not daft... ;-)
Is it daft to want my_rational<x,1> to be a conforming MPL integral constant? -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" wrote
"Andy Little" writes:
I am arguing for a normalised version, so for my_rational<2,8>, my_rational<3,12> and my_rational<5,20> among others, the normalised version is my_rational<1,4> and thats what I think rational<...>::type should return.
Why should that normalization be done eagerly? I can see no good reason for it.
Numerator and denominator members are evaluated already . I guess you could remove them.... [cut]
Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?
Who wants special cases? integral constant can be converted to a rational constant , but not necessarily the other way. numerator<T> and denominator<T> functions are provided for integration with integral constants. regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
"David Abrahams" wrote
"Andy Little" writes:
I am arguing for a normalised version, so for my_rational<2,8>, my_rational<3,12> and my_rational<5,20> among others, the normalised version is my_rational<1,4> and thats what I think rational<...>::type should return.
Why should that normalization be done eagerly? I can see no good reason for it.
Numerator and denominator members are evaluated already . I guess you could remove them....
I don't see what the presence of numerator and denominator has to do with normalization.
[cut]
Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?
Who wants special cases?
Who suggested a special case?
integral constant can be converted to a rational constant, but not necessarily the other way.
Don't forget that the types are all known at compile-time. The usual runtime logic doesn't necessarily apply. A conversion from my_rational<x,1> to int_<x> is not a narrowing conversion. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" wrote
"Andy Little" writes:
I don't see what the presence of numerator and denominator has to do with normalization.
They should be typedefs for the input parameters? [cut]
Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?
Who wants special cases?
Who suggested a special case?
Whoever said , " Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?" .
integral constant can be converted to a rational constant, but not necessarily the other way.
Don't forget that the types are all known at compile-time. The usual runtime logic doesn't necessarily apply. A conversion from my_rational<x,1> to int_<x> is not a narrowing conversion.
Conversion is fine. Thats not what you said above. Actually I already use conversions in my boosted version of my pqs library, so that user can use integer rather than rational dimensions. It works fine. cheers Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
"David Abrahams" wrote
"Andy Little" writes:
I don't see what the presence of numerator and denominator has to do with normalization.
They should be typedefs for the input parameters?
What does that have to do with normalization?
Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?
Who wants special cases?
Who suggested a special case?
Whoever said , " Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?" .
That doesn't require any special case code.
integral constant can be converted to a rational constant, but not necessarily the other way.
Don't forget that the types are all known at compile-time. The usual runtime logic doesn't necessarily apply. A conversion from my_rational<x,1> to int_<x> is not a narrowing conversion.
Conversion is fine. Thats not what you said above.
No, it's not what I said above. Remember, the usual runtime logic doesn't necessarily apply. my_rational<x,1> can be an integral constant *at compile time*. I'm not sure it's useful, but it's not insane. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" wrote
"Andy Little" writes:
"David Abrahams" wrote
"Andy Little" writes:
I don't see what the presence of numerator and denominator has to do with normalization.
They should be typedefs for the input parameters?
What does that have to do with normalization?
Are you referring to my use of the word 'normalisation' to mean making my_rational<2,8>::type == my_rational<1,4>? Maybe the use of the word normalisation here is not correct. Is that the problem? [cut]
Who suggested a special case?
Whoever said , " Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?" .
That doesn't require any special case code.
At least in terms of the value and value_type members it does: http://www.boost.org/libs/mpl/doc/refmanual/integral-constant.html [cut]
Conversion is fine. Thats not what you said above.
No, it's not what I said above. Remember, the usual runtime logic doesn't necessarily apply. my_rational<x,1> can be an integral constant *at compile time*. I'm not sure it's useful, but it's not insane.
Its difficult to know what you mean. Do you mean something like: template < typename Numerator, typename Denominator
where Denominator == One struct my_rational : Numerator {/*...*/}; ( forgetting for a moment the other cases ) regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
"David Abrahams" wrote
"Andy Little" writes:
"David Abrahams" wrote
"Andy Little" writes:
I don't see what the presence of numerator and denominator has to do with normalization.
They should be typedefs for the input parameters?
Hmm, is that meant to be a question?
What does that have to do with normalization?
Are you referring to my use of the word 'normalisation'
Yes.
to mean making my_rational<2,8>::type == my_rational<1,4>? Maybe the use of the word normalisation here is not correct. Is that the problem?
No. Please take me literally. I don't see any relationship between whether we provide numerator/denominator member typedefs and normalisation (or normalization).
[cut]
Who suggested a special case?
Whoever said , " Is it daft to want my_rational<x,1> to be a conforming MPL integral constant?" .
That doesn't require any special case code.
At least in terms of the value and value_type members it does:
http://www.boost.org/libs/mpl/doc/refmanual/integral-constant.html
I don't see why the type member is an issue, but yeah, you're right, the value member would be a problem.
Conversion is fine. Thats not what you said above.
No, it's not what I said above. Remember, the usual runtime logic doesn't necessarily apply. my_rational<x,1> can be an integral constant *at compile time*. I'm not sure it's useful, but it's not insane.
Its difficult to know what you mean. Do you mean something like:
template < typename Numerator, typename Denominator
where Denominator == One struct my_rational : Numerator {/*...*/};
Yes, something like that. Maybe a silly idea, but not insane. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" wrote
"Andy Little" writes:
I don't see what the presence of numerator and denominator has to do with normalization.
They should be typedefs for the input parameters?
Hmm, is that meant to be a question?
As it stands in both my and Cromwells version the numerator and denominator are those of the (so-called) normalized version. This was carried over from the runtime version by Matthias Schabel in his original compile-time rational. IOW to the compile time rational veterans thats how its always been and we thought it worked fine. The rationale is that rational is primarily a math entity, whereas integral can be used as an id and for counting, iterating etc. So the question is do you think they should rather be typedefs for the input parameters?
What does that have to do with normalization?
Are you referring to my use of the word 'normalisation'
Yes.
to mean making my_rational<2,8>::type == my_rational<1,4>? Maybe the use of the word normalisation here is not correct. Is that the problem?
No. Please take me literally. I don't see any relationship between whether we provide numerator/denominator member typedefs and normalisation (or normalization).
As it stands these two typedefs are normalized versions of the Numerator and Denominator parameters. [cut]
Its difficult to know what you mean. Do you mean something like:
template < typename Numerator, typename Denominator
where Denominator == One struct my_rational : Numerator {/*...*/};
Yes, something like that. Maybe a silly idea, but not insane.
I experimented with the integral / rational relationship. My view is that it is unwise to couple the two together too closely. One example is in division. divides<int<1>,int<2> > isnt the same as divides<int_<1>, rational<2,1> >, That can only be enforced if there is no hidden conversion from rational to integral. regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
"David Abrahams" wrote
"Andy Little" writes:
I don't see what the presence of numerator and denominator has to do with normalization.
They should be typedefs for the input parameters?
Hmm, is that meant to be a question?
As it stands in both my and Cromwells version the numerator and denominator are those of the (so-called) normalized version. This was carried over from the runtime version by Matthias Schabel in his original compile-time rational. IOW to the compile time rational veterans thats how its always been and we thought it worked fine. The rationale is that rational is primarily a math entity, whereas integral can be used as an id and for counting, iterating etc. So the question is do you think they should rather be typedefs for the input parameters?
As it stands these two typedefs are normalized versions of the Numerator and Denominator parameters.
If you're trying to save cycles at compilation time by normalizing lazily, then of course the numerator and denominator typedefs can't be normalized. So, sure, typedefs for the template arguments sound fine to me. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" wrote
As it stands these two typedefs are normalized versions of the Numerator and Denominator parameters.
If you're trying to save cycles at compilation time by normalizing lazily, then of course the numerator and denominator typedefs can't be normalized. So, sure, typedefs for the template arguments sound fine to me.
I wouldnt mind this from a practical point of view. I believe that Cromwells implementation of gcd is overkill for my needs, so I guess that would make it easier to customise. Overall though I am opposed to it because I believe the current interface is superior from a users point of view and its a classic case of optimisation ruling the interface. In the case of dimensional analysis in a quantity, it seems to be perfectly possible to mix rationals and integral constants in a mpl container, though some care needs to be taken with the maths ( It may be worth using a custom division operator). In use for dimensional analysis rationals are actually pretty rare (integral constants can be substituted in the vast majority of cases) and all rationals used have a very small range of values, so I hope that any poor compile time performance of rationals will not have such a great effect. In fact I think that division is the only operation where extra care is required though any operation involving a rational requires normalisation if its involved in math and comparisons etc. I guess it might be worth getting Cromwell Enage's view as to whether he feels changing the current interface is worthwhile. regards Andy Little

--- Andy Little wrote:
If you're trying to save cycles at compilation time by normalizing lazily, then of course the numerator and denominator typedefs can't be normalized. So, sure, typedefs for the template arguments sound fine to me.
I wouldnt mind this from a practical point of view. I believe that Cromwell's implementation of gcd is overkill for my needs, so I guess that would make it easier to customise.
Overall though I am opposed to it because I believe the current interface is superior from a user's
Well, the "generic" implementation is overkill because it can't make too many assumptions about the input metatype. For integral constants, you can specialize gcd_impl and substitute your own implementation (e.g. binary GCD). For big_integral, I've found that following Peder's approach--favoring BOOST_STATIC_CONSTANT expressions over typedefs whenever possible--drastically cuts down compile times at a cost of slightly reduced portability, which is not a great concern right now. Perhaps a similar approach to gcd_impl will also serve you well. point
of view and it's a classic case of optimisation ruling the interface.
In the case of dimensional analysis in a quantity, it seems to be perfectly possible to mix rationals and integral constants in an mpl container, though some care needs to be taken with the maths. (It may be worth using a custom division operator). In use for dimensional analysis rationals are actually pretty rare (integral constants can be substituted in the vast majority of cases) and all rationals used have a very small range of values, so I hope that any poor compile time performance of rationals will not have such a great effect. In fact I think that division is the only operation where extra care is required, though any operation involving a rational requires normalisation if it's involved in math and comparisons etc.
I guess it might be worth getting Cromwell Enage's view as to whether he feels changing the current interface is worthwhile.
One of the capabilities I tried to build into the library was the ability for advanced numeric metafunctions to treat rationals, mixed_numbers, and now doubles as generically as possible. To this end, I provided the is_negative, numerator, denominator, whole_part, and rational_part numeric metafunctions, each with a corresponding _impl metafunction class. Any real numeric metatype on which these metafunctions (and, of course, the arithmetic and comparison metafunctions) can operate is considered to be implementing the "current interface". (In order to get intelligible output, one must also specialize the runtime_value_impl metafunction class for the metatype, and/or override the << operator for output streams.) For my part, I'll provide the following macros in the next version: BOOST_MPL_MATH_NUMERATOR_OF_MIXED_NUMBER(tag) BOOST_MPL_MATH_DENOMINATOR_OF_MIXED_NUMBER(tag) BOOST_MPL_MATH_WHOLE_PART_OF_RATIONAL(tag) BOOST_MPL_MATH_RATIONAL_PART_OF_RATIONAL(tag) For example, Peder Holt's double requires specializations of is_negative_impl, whole_part, and rational_part, as well as the arithmetic and comparison operators. Once they are provided, we can add the following two statements: BOOST_MPL_MATH_NUMERATOR_OF_MIXED_NUMBER(double_tag) BOOST_MPL_MATH_DENOMINATOR_OF_MIXED_NUMBER(double_tag) Voila! Peder Holt's double is now a Real Numeric Constant. For the problem space you describe, you can start by changing rational_c to your liking, as the numerator and denominator are guaranteed to be primitive integral constants. Once you do so, you'll have to provide a corresponding rational_c_tag that inherits from prior<rational_tag>::type, a BOOST_MPL_AUX_NUMERIC_CAST specialization from rational_c to rational, and specializations of is_negative_impl, numerator_impl, and denominator_impl. (And don't forget runtime_value_impl and <<.) Then you can finish it off with: BOOST_MPL_MATH_WHOLE_PART_OF_RATIONAL(rational_c_tag) BOOST_MPL_MATH_RATIONAL_PART_OF_RATIONAL(rational_c_tag) HTH! Cromwell D. Enage __________________________________ Yahoo! Mail - PC Magazine Editors' Choice 2005 http://mail.yahoo.com

--- Cromwell Enage wrote:
For my part, I'll provide the following macros in the next version:
BOOST_MPL_MATH_NUMERATOR_OF_MIXED_NUMBER(tag) BOOST_MPL_MATH_DENOMINATOR_OF_MIXED_NUMBER(tag) BOOST_MPL_MATH_WHOLE_PART_OF_RATIONAL(tag) BOOST_MPL_MATH_RATIONAL_PART_OF_RATIONAL(tag)
Done. Cromwell D. Enage __________________________________ Yahoo! Mail - PC Magazine Editors' Choice 2005 http://mail.yahoo.com

On 10/27/05 9:43 AM, "Cromwell Enage" <sponage@yahoo.com> wrote:
--- Cromwell Enage wrote:
For my part, I'll provide the following macros in the next version:
BOOST_MPL_MATH_NUMERATOR_OF_MIXED_NUMBER(tag) BOOST_MPL_MATH_DENOMINATOR_OF_MIXED_NUMBER(tag) BOOST_MPL_MATH_WHOLE_PART_OF_RATIONAL(tag) BOOST_MPL_MATH_RATIONAL_PART_OF_RATIONAL(tag)
Done.
Is BOOST_MPL_MATH_RATIONAL_PART_OF_RATIONAL a re-statement of the rational number itself? Or is it supposed to be the remainder after taking out the "whole" part? If the former, then we probably need another macro for the latter. If the latter, then the name should have "FRACTIONAL" replacing the first "RATIONAL," since "fractional" and not "rational" better describes a left-over bit. (Rational numbers are a generalization of fractions that include values with absolute values greater than one, i.e. a numerator larger than its denominator [in absolute value].) -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"David Abrahams" <dave@boost-consulting.com> wrote
"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
No, it's not what I said above. Remember, the usual runtime logic doesn't necessarily apply. my_rational<x,1> can be an integral constant *at compile time*. I'm not sure it's useful, but it's not insane.
BTW Another other issue in integrating tightly with integral constants is division. You need a special e.g rational_divides<IntorRatA,IntorRatB> function. regards Andy Little

David Abrahams wrote:
"Andy Little" <andy@servocomm.freeserve.co.uk> writes: <snip>
integral constant can be converted to a rational constant, but not necessarily the other way. Don't forget that the types are all known at compile-time. The usual runtime logic doesn't necessarily apply. A conversion from my_rational<x,1> to int_<x> is not a narrowing conversion. Conversion is fine. Thats not what you said above.
No, it's not what I said above. Remember, the usual runtime logic doesn't necessarily apply. my_rational<x,1> can be an integral constant *at compile time*. I'm not sure it's useful, but it's not insane.
If you for some reason still think this, why not eagerly evaluate template<typename Num> rational<Num,1> to Num, since we are already eagerly normalising? -- don't quote this
participants (5)
-
Andy Little
-
Cromwell Enage
-
Daryle Walker
-
David Abrahams
-
Simon Buchan