23 General utilities library [utilities]

23.16 Compile-time rational arithmetic [ratio]

23.16.1 In general [ratio.general]

В этом подразделе описывается библиотека соотношений. Он предоставляет шаблон класса, ratio который точно представляет любое конечное рациональное число с числителем и знаменателем, представленным константами типа времени компиляции intmax_­t.

В этом подпункте имена параметров шаблона используются для выражения требований к типу. Если параметр шаблона назван R1 или R2, а аргумент шаблона не является специализацией ratio шаблона, программа имеет неправильный формат.

23.16.2 Header <ratio> synopsis [ratio.syn]

namespace std {
  // [ratio.ratio], class template ratio
  template <intmax_t N, intmax_t D = 1> class ratio;

  // [ratio.arithmetic], ratio arithmetic
  template <class R1, class R2> using ratio_add = see below;
  template <class R1, class R2> using ratio_subtract = see below;
  template <class R1, class R2> using ratio_multiply = see below;
  template <class R1, class R2> using ratio_divide = see below;

  // [ratio.comparison], ratio comparison
  template <class R1, class R2> struct ratio_equal;
  template <class R1, class R2> struct ratio_not_equal;
  template <class R1, class R2> struct ratio_less;
  template <class R1, class R2> struct ratio_less_equal;
  template <class R1, class R2> struct ratio_greater;
  template <class R1, class R2> struct ratio_greater_equal;

  template <class R1, class R2>
    inline constexpr bool ratio_equal_v = ratio_equal<R1, R2>::value;
  template <class R1, class R2>
    inline constexpr bool ratio_not_equal_v = ratio_not_equal<R1, R2>::value;
  template <class R1, class R2>
    inline constexpr bool ratio_less_v = ratio_less<R1, R2>::value;
  template <class R1, class R2>
    inline constexpr bool ratio_less_equal_v = ratio_less_equal<R1, R2>::value;
  template <class R1, class R2>
    inline constexpr bool ratio_greater_v = ratio_greater<R1, R2>::value;
  template <class R1, class R2>
    inline constexpr bool ratio_greater_equal_v = ratio_greater_equal<R1, R2>::value;

  // [ratio.si], convenience SI typedefs
  using yocto = ratio<1, 1'000'000'000'000'000'000'000'000>;  // see below
  using zepto = ratio<1,     1'000'000'000'000'000'000'000>;  // see below
  using atto  = ratio<1,         1'000'000'000'000'000'000>;
  using femto = ratio<1,             1'000'000'000'000'000>;
  using pico  = ratio<1,                 1'000'000'000'000>;
  using nano  = ratio<1,                     1'000'000'000>;
  using micro = ratio<1,                         1'000'000>;
  using milli = ratio<1,                             1'000>;
  using centi = ratio<1,                               100>;
  using deci  = ratio<1,                                10>;
  using deca  = ratio<                               10, 1>;
  using hecto = ratio<                              100, 1>;
  using kilo  = ratio<                            1'000, 1>;
  using mega  = ratio<                        1'000'000, 1>;
  using giga  = ratio<                    1'000'000'000, 1>;
  using tera  = ratio<                1'000'000'000'000, 1>;
  using peta  = ratio<            1'000'000'000'000'000, 1>;
  using exa   = ratio<        1'000'000'000'000'000'000, 1>;
  using zetta = ratio<    1'000'000'000'000'000'000'000, 1>;  // see below
  using yotta = ratio<1'000'000'000'000'000'000'000'000, 1>;  // see below
}

23.16.3 Class template ratio [ratio.ratio]

namespace std {
  template <intmax_t N, intmax_t D = 1>
  class ratio {
  public:
    static constexpr intmax_t num;
    static constexpr intmax_t den;
    using type = ratio<num, den>;
  };
}

Если аргумент шаблона D равен нулю или равен абсолютным значениям любого из аргументов шаблона N и D не может быть представлен по типу intmax_­t, программа имеет неправильный формат. [ Note: Эти правила гарантируют, что можно избежать бесконечных соотношений и что для любого отрицательного входа существует представимое значение его абсолютного значения, которое является положительным. В представлении с дополнением до двух это исключает самое отрицательное значение. ] end note

Статические элементы данных num и den должны иметь следующие значения, где gcd представляет наибольший общий делитель абсолютных значений N и D:

  • num имеет ценность sign(N) * sign(D) * abs(N) / gcd.

  • den имеет ценность abs(D) / gcd.

23.16.4 Arithmetic on ratios [ratio.arithmetic]

Каждый из шаблонов псевдонимов ratio_­add, ratio_­subtract, ratio_­multiplyи ratio_­divide обозначает результат арифметического вычисления на два ratioсекунд R1 и R2. При вычислении X и Y вычислении (при отсутствии арифметического переполнения), как указано в таблице 51, каждый псевдоним обозначает ratio<U, V> такой U же, как ratio<X, Y>​::​num и V такой же, как ratio<X, Y>​::​den.

Если это не возможно представить U или V с intmax_­t, программа плохо сформирована. В противном случае реализация должна давать правильные значения U и V. Если невозможно представить X или Y с intmax_­t, программа плохо сформирована, если реализация не дает правильных значений U и V.

Таблица 51 - Выражения, используемые для выполнения арифметики отношений
ТипЗначение XЗначение Y
ratio_­add<R1, R2> R1​::​num * R2​::​den + R1​::​den * R2​::​den
R2​::​num * R1​::​den
ratio_­subtract<R1, R2> R1​::​num * R2​::​den - R1​::​den * R2​::​den
R2​::​num * R1​::​den
ratio_­multiply<R1, R2> R1​::​num * R2​::​num R1​::​den * R2​::​den
ratio_­divide<R1, R2> R1​::​num * R2​::​den R1​::​den * R2​::​num

[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_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");

// The following cases may cause the program to be ill-formed under some implementations
static_assert(ratio_add<ratio<1, INT_MAX>, ratio<1, INT_MAX>>::num == 2,
  "1/MAX+1/MAX == 2/MAX");
static_assert(ratio_add<ratio<1, INT_MAX>, ratio<1, INT_MAX>>::den == INT_MAX,
  "1/MAX+1/MAX == 2/MAX");
static_assert(ratio_multiply<ratio<1, INT_MAX>, ratio<INT_MAX, 2>>::num == 1,
  "1/MAX * MAX/2 == 1/2");
static_assert(ratio_multiply<ratio<1, INT_MAX>, ratio<INT_MAX, 2>>::den == 2,
  "1/MAX * MAX/2 == 1/2");

end example]

23.16.5 Comparison of ratios [ratio.comparison]

template <class R1, class R2> struct ratio_equal : bool_constant<R1::num == R2::num && R1::den == R2::den> { };

template <class R1, class R2> struct ratio_not_equal : bool_constant<!ratio_equal_v<R1, R2>> { };

template <class R1, class R2> struct ratio_less : bool_constant<see below> { };

Если R1​::​num × R2​::​den меньше R2​::​num × R1​::​den, ratio_­less<R1, R2> должно быть производным от bool_­constant<true>; в противном случае он должен быть получен из bool_­constant<false>. Реализации могут использовать другие алгоритмы для вычисления этого отношения, чтобы избежать переполнения. Если происходит переполнение, программа имеет неправильный формат.

template <class R1, class R2> struct ratio_less_equal : bool_constant<!ratio_less_v<R2, R1>> { };

template <class R1, class R2> struct ratio_greater : bool_constant<ratio_less_v<R2, R1>> { };

template <class R1, class R2> struct ratio_greater_equal : bool_constant<!ratio_less_v<R1, R2>> { };

23.16.6 SI types for ratio [ratio.si]

Для каждого из typedef-names yocto, zepto, zetta, и yotta, если оба из констант , используемых в его описании, представима intmax_­t, должен быть определен ЬурейеЕ; если какая-либо из констант не может быть представлена ​​с помощью intmax_­t, определение типа не должно определяться.