Boost logo

Boost :

Subject: Re: [boost] [ratio] metafunction ratio_subtract
From: Howard Hinnant (howard.hinnant_at_[hidden])
Date: 2009-12-06 18:18:19


On Dec 6, 2009, at 3:43 PM, vicente.botet wrote:

> Hi Beman, Hi Howard,
>
> With current implementation of the metafunction ratio_subtract I get the type from the test ratio_test.cpp
>
> User1::Distance d( User1::mile(110) );
> User1::Time t( boost::chrono::hours(2) );
>
> typeof (d/t) is User1::quantity<boost::ratio<1,-1>, boost::ratio<1,1> >
>
> So the following assignation do not works
>
> User1::Speed s = d / t;
>
> as User1::Speed is defined as
>
> typedef quantity<boost::ratio<1>, boost::ratio<0> > Time; // second
> typedef quantity<boost::ratio<0>, boost::ratio<1> > Distance; // meter
> typedef quantity<boost::ratio<-1>, boost::ratio<1> > Speed; // meter/second
>
> The code is a little bit triky, and I have not taken the time to understand why the resulting type is
> User1::quantity<boost::ratio<1,-1>, boost::ratio<1,1> >
> and not
> <boost::ratio<-1,1>, boost::ratio<1,1> > User1::quantity

There must be a bug in the ratio formation of num and den. It should not be possible to form a ratio such that ratio::den is not positive. [ratio.ratio]/1 states that D shall not be 0. [ratio.ratio]/2 specifies that gcd operates on the absolute values of N and D (and so gcd must be positive). den is specified to be abs(D)/gcd, which must be positive.

> I have replaced the type by
>
> typedef ratio<R1::num * R2::den - R2::num * R1::den,R1::den * R2::den> aux_type;
> typedef ratio<aux_type::num ,aux_type::den > type; // get normalized type
>
> to follow the recommendation "The nested typedef type shall be a synonym for ratio<T1, T2> where T1 has the value R1::num *R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den."
>
> and every thing is OK (See below the replaced code)
>
> I'm doing something wrong?

No, you're doing something right by investigating this mystery. :-)

I've lost the link to the code you're working with. Could you post it?

The original implementation of ratio_subtract (thank you for including it below) is designed to be equivalent to your substitution, but less susceptible to overflow, by performing exact division as soon as possible (get integers as low as possible, as soon as possible).

I'm not sure where your example of computing speed from distance and time involves subtraction. But I'm interested to help you get to the bottom of it.

-Howard

>
> Best,
> _____________________
> Vicente Juan Botet Escribá
>
>
>
> template <class R1, class R2>
> struct ratio_subtract
> {
> private:
> #if 1
> typedef ratio<R1::num * R2::den - R2::num * R1::den,R1::den * R2::den> aux_type;
> #else
> static const boost::intmax_t gcd_n1_n2 = detail::static_gcd<R1::num, R2::num>::value;
> static const boost::intmax_t gcd_d1_d2 = detail::static_gcd<R1::den, R2::den>::value;#endif
> public:
> //The nested typedef type shall be a synonym for ratio<T1, T2> where T1 has the value
> // R1::num *R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den.
> #if 1
> typedef ratio<aux_type::num ,aux_type::den > type;
> #else
> typedef typename ratio_multiply
> <
> ratio<gcd_n1_n2, R1::den / gcd_d1_d2>,
> ratio
> <
> detail::ll_sub
> <
> detail::ll_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
> detail::ll_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
>> ::value,
> R2::den
>>
>> ::type type;
> #endif
> };
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk