**Document number**: P1050R0

**Date**: 2018-05-07

**Reply-to**: John McFarlane, fixed-point@john.mcfarlane.name

**Audience**: SG6, LEWG

This paper introduces a fractional number type which stores pairs of integer numerators and denominators. It avoids precision loss commonly associated with the storage of single-number quotients. It also helps express intent when initializing fixed-point types with the results of division operations.

Rational numbers provide a headache for digital number types such as the fundamental scalars. We already have `std::ratio`

-- mostly as a necessary way of expressing different static scales in `std::chrono`

. There has previously been discussion of sophisticated, general purpose bounded [P0101] and unbounded [P0101] rationals. Boost has a rational type [Boost].

This paper proposes a fractional type that is compatible with the compositional approach detailed in [P0554]. As such it is designed to provide a zero-overhead abstraction over pairs of integers while also being an expressive, user-friendly, general-purpose statically-sized number type when combined with other numeric components.

The reason for proposing a fractional type at this time is because it serves a specific role in initialization of the fixed-point numbers described in [P0037].

Class template, `fixed_point<>`

from [P0037] can be initialized with integer and floating-point values. It is desirable that `fixed_point<>`

values also be the quotient in a division operation. A `divide`

function was previously proposed in [P0037]:

```
auto a = divide(1, 3);
```

Straight away the question arises: what should be the resolution of `a`

? The solution proposed in [P0106] is to determine the number of fractional digits from the number of fractional digits in the numerator and integer digits in the denominator. In the example above, `a`

has 31 fractional digits because literal, `3`

, has 31 integer digits. The result has value, 0.333333333022892475128173828125.

This solution is problematic when one considers all of the ways that `1`

or `3`

can be represented. For example, using `elastic_integer<>`

[P0828] as the inputs

```
auto b = divide(elastic_integer<1>{1}, elastic_integer<2>{3});
```

results in a `fixed_point`

type with only 2 fractional digits. The resultant approximation of `1/3`

is `0.25`

. This is unlikely to be the desired result in most cases.

Specifying the output type is one solution:

```
auto c = divide<fixed_point<int, -16>>(1, 3);
auto d = divide<fixed_point<int, -16>>(elastic_integer<1>{1}, elastic_integer<2>{3});
```

Both `c`

and `d`

have values, `0.3333282470703125`

. However, it is not entirely clear that introducing a named function specifically for this purpose is necessary, nor whether the interface is sufficiently intuitive.

By introducing a fractional type, `fractional`

```
template<class Numerator, class Denominator>
struct fractional {
// ...
Numerator numerator;
Denominator denominator;
};
```

we can express the same intent using only types:

```
auto a = fixed_point{fractional{1, 3}};
auto b = fixed_point{fractional{elastic_integer<1>{1}, elastic_integer<2>{3}}};
auto c = fixed_point<int, -16>{fractional{1, 3}};
auto d = fixed_point<int, -16>{fractional{elastic_integer<1>{1}, elastic_integer<2>{3}}};
```

```
template<class Numerator, class Denominator>
struct fractional {
using numerator_type = Numerator;
using denominator_type = Denominator;
explicit constexpr fractional(const Numerator& n, const Denominator& d);
explicit constexpr fractional(const Numerator& n);
template<class Scalar, _impl::enable_if_t<std::is_floating_point<Scalar>::value, int> = 0>
explicit constexpr operator Scalar() const;
numerator_type numerator;
denominator_type denominator = 1;
};
template<class Numerator, class Denominator>
fractional(const Numerator& n, const Denominator&)
-> fractional<Numerator, Denominator>;
template<class Numerator>
fractional(Numerator const& n)
-> fractional<Numerator, int>;
template<class Numerator, class Denominator>
constexpr auto reduce(fractional<Numerator, Denominator> const& f);
template<class LhsNumerator, class LhsDenominator, class RhsNumerator, class RhsDenominator>
constexpr auto operator+(
fractional<LhsNumerator, LhsDenominator> const& lhs,
fractional<RhsNumerator, RhsDenominator> const& rhs)
-> decltype(make_fractional(
lhs.numerator*rhs.denominator+rhs.numerator*lhs.denominator, lhs.denominator*rhs.denominator));
template<class LhsNumerator, class LhsDenominator, class RhsNumerator, class RhsDenominator>
constexpr auto operator-(
fractional<LhsNumerator, LhsDenominator> const& lhs,
fractional<RhsNumerator, RhsDenominator> const& rhs)
-> decltype(make_fractional(
lhs.numerator*rhs.denominator-rhs.numerator*lhs.denominator, lhs.denominator*rhs.denominator));
template<class LhsNumerator, class LhsDenominator, class RhsNumerator, class RhsDenominator>
constexpr auto operator*(
fractional<LhsNumerator, LhsDenominator> const& lhs,
fractional<RhsNumerator, RhsDenominator> const& rhs)
-> decltype(make_fractional(lhs.numerator*rhs.numerator, lhs.denominator*rhs.denominator));
template<class LhsNumerator, class LhsDenominator, class RhsNumerator, class RhsDenominator>
constexpr auto operator/(
fractional<LhsNumerator, LhsDenominator> const& lhs,
fractional<RhsNumerator, RhsDenominator> const& rhs)
-> decltype(make_fractional(lhs.numerator*rhs.denominator, lhs.denominator*rhs.numerator));
template<class LhsNumerator, class LhsDenominator, class RhsNumerator, class RhsDenominator>
constexpr auto operator==(
fractional<LhsNumerator, LhsDenominator> const& lhs,
fractional<RhsNumerator, RhsDenominator> const& rhs);
template<class LhsNumerator, class LhsDenominator, class RhsNumerator, class RhsDenominator>
constexpr auto operator!=(
fractional<LhsNumerator, LhsDenominator> const& lhs,
fractional<RhsNumerator, RhsDenominator> const& rhs);
```

`fractional`

is implemented as part of the CNL library (header, tests, fixed_point integration).