Document Number:N3131=10-0121
Date:2010-08-20
Author:Anthony Williams
Just Software Solutions Ltd

N3131: Compile-time rational arithmetic and overflow

Comment GB 89 on the FCD (see N3102) raised the issue of how compile-time rational arithmetic should be done when the result is representable, but a simple application of arithmetic rules would result in overflow.

e.g. ratio_multiply<ratio<INTMAX_MAX,2>,ratio<2,INTMAX_MAX>> can be reduced to ratio<1,1>, but the direct result of ratio<INTMAX_MAX*2,INTMAX_MAX*2> would result in overflow.

The consensus in Rapperswil was to allow but not require the implementation to handle such overflow if the final result was representable.

Proposed Wording

Change the wording in 20.6.2 [ratio.arithmetic] as follows:

Implementations may use other algorithms to compute these values. If overflow occurs in the calculation of the result, the program is ill-formed. [Note: Implementations are encouraged to use alternative algorithms that avoid overflow in the calculation if the final result is representable. Such provision is conditionally supported. -- End Note]

template <class R1, class R2> using ratio_add = see below;

The type ratio_add<R1, R2> shall be a synonym for ratio<T1,T2> ratio<U, V> such that ratio<U,V>::num and ratio<U,V>::den are the same as the corresponding members of ratio<T1,T2> would be in the absence of arithmetic overflow where T1 has the value R1::num * R2::den + R2::num * R1::den and T2 has the value R1::den * R2::den. If the required values of ratio<U,V>::num and ratio<U,V>::den cannot be represented in intmax_t then the program is illformed. Correct calculation of the result if either of T1 or T2 cannot be represented in intmax_t is conditionally supported ([defns.cond.supp])

template <class R1, class R2> using ratio_subtract = see below;

The type ratio_subtract<R1, R2> shall be a synonym for ratio<T1,T2> ratio<U, V> such that ratio<U,V>::num and ratio<U,V>::den are the same as the corresponding members of ratio<T1,T2> would be in the absence of arithmetic overflow where T1 has the value R1::num * R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den. If the required values of ratio<U,V>::num and ratio<U,V>::den cannot be represented in intmax_t then the program is illformed. Correct calculation of the result if either of T1 or T2 cannot be represented in intmax_t is conditionally supported ([defns.cond.supp])

template <class R1, class R2> using ratio_multiply = see below;

The type ratio_multiply<R1, R2> shall be a synonym for ratio<T1,T2> ratio<U, V> such that ratio<U,V>::num and ratio<U,V>::den are the same as the corresponding members of ratio<T1,T2> would be in the absence of arithmetic overflow where T1 has the value R1::num * R2::num and T2 has the value R1::den * R2::den. If the required values of ratio<U,V>::num and ratio<U,V>::den cannot be represented in intmax_t then the program is illformed. Correct calculation of the result if either of T1 or T2 cannot be represented in intmax_t is conditionally supported ([defns.cond.supp])

template <class R1, class R2> using ratio_divide = see below;

The type ratio_divide<R1, R2> shall be a synonym for ratio<T1,T2> ratio<U, V> such that ratio<U,V>::num and ratio<U,V>::den are the same as the corresponding members of ratio<T1,T2> would be in the absence of arithmetic overflow where T1 has the value R1::num * R2::den and T2 has the value R1::den * R2::num. If the required values of ratio<U,V>::num and ratio<U,V>::den cannot be represented in intmax_t then the program is illformed. Correct calculation of the result if either of T1 or T2 cannot be represented in intmax_t is conditionally supported ([defns.cond.supp])

[Example --

static_assert(ratio_add<ratio<1,3>,ratio<1,6>>::num==1,"1/3+1/6==1/2");
static_assert(ratio_add<ratio<1,3>,ratio<1,6>>::den==2,"1/3+1/6==1/2");
static_assert(ratio_add<ratio<1,INTMAX_MAX>,ratio<1,INTMAX_MAX>>::num==2,"1/MAX+1/MAX==2/MAX");  // conditionally supported
static_assert(ratio_add<ratio<1,INTMAX_MAX>,ratio<1,INTMAX_MAX>>::den==INTMAX_MAX,"1/MAX+1/MAX==2/MAX");  // conditionally supported

static_assert(ratio_multiply<ratio<1,3>,ratio<3,2>>::num==1,"1/3*3/2==1/2");
static_assert(ratio_multiply<ratio<1,3>,ratio<3,2>>::den==2,"1/3*3/2==1/2");

static_assert(ratio_multiply<ratio<1,INTMAX_MAX>,ratio<INTMAX_MAX,2>>::num==1,"1/MAX * MAX/2==1/2");  // conditionally supported
static_assert(ratio_multiply<ratio<1,INTMAX_MAX>,ratio<INTMAX_MAX,2>>::den==2,"1/MAX * MAX/2==1/2");  // conditionally supported
--End Example]