Как проверить, переполняется ли std :: ratio_multiply? - PullRequest
0 голосов
/ 01 мая 2020

Мне нужна функция, которая даст мне тип 'std :: ratio_multiply', если нет переполнения, или список оригинальных типов rat ios, если переполнение.

1 Ответ

1 голос
/ 01 мая 2020

Достаточным условием будет проверка того, что журнал числителей и знаменателей суммируется с меньшим, чем журнал std::numeric_traits<std::intmax_t>::max(), но это исключает некоторые вещи, которые могут быть сведены к представимым значениям.

Это можно улучшить рассматривая gcds

template <typename R1, typename R2, bool>
struct safe_ratio_multiply_impl;

template <typename R1, typename R2>
struct safe_ratio_multiply_impl<R1, R2, true>
{
    using type = std::ratio_multiply<R1, R2>;
}

template <typename R1, typename R2>
struct safe_ratio_multiply_impl<R1, R2, false>
{
    using type = std::tuple<R1, R2>;
}

constexpr intmax_t log(intmax_t number, intmax_t acc = 0) {
    return number <= 1 ? acc : log(number / 2, acc + 1);
}

constexpr bool is_safe_multiple(std::intmax_t N1, std::intmax_t D1, std::intmax_t N2, std::intmax_t D2)
{
    auto limit = log(std::numeric_traits<std::intmax_t>::max()) + log(std::gcd(N1, R2)) + log(std::gcd(N2, R1));
    auto num = (log(N1) + log(N2)) < limit;
    auto den = (log(R2) + log(R2)) < limit;
    return num && den;
}

template <typename R1, typename R2>
using safe_ratio_multiply = typename safe_ratio_multiply_impl<R1, R2, is_safe_multiple(R1::num, R1::den, R2::num, R2::den)>::type;
...