diff --git a/test/metabench/ratio/ratio_type_constexpr.h b/test/metabench/ratio/ratio_type_constexpr.h index 337ef42b..14826324 100644 --- a/test/metabench/ratio/ratio_type_constexpr.h +++ b/test/metabench/ratio/ratio_type_constexpr.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace units { @@ -66,16 +67,33 @@ namespace units { namespace detail { + static constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs) + { + constexpr std::uintmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4); + + const std::uintmax_t a0 = detail::abs(lhs) % c; + const std::uintmax_t a1 = detail::abs(lhs) / c; + const std::uintmax_t b0 = detail::abs(rhs) % c; + const std::uintmax_t b1 = detail::abs(rhs) / c; + + Expects(a1 == 0 || b1 == 0); // overflow in multiplication + Expects(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication + Expects(b0 * a0 <= INTMAX_MAX); // overflow in multiplication + Expects((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0); // overflow in multiplication + + return lhs * rhs; + } + template struct ratio_multiply { private: - static constexpr intmax_t gcd1 = std::gcd(R1::num, R2::den); - static constexpr intmax_t gcd2 = std::gcd(R2::num, R1::den); + static constexpr std::intmax_t gcd1 = std::gcd(R1::num, R2::den); + static constexpr std::intmax_t gcd2 = std::gcd(R2::num, R1::den); public: - using type = ratio<(R1::num / gcd1) * (R2::num / gcd2), (R1::den / gcd2) * (R2::den / gcd1)>; - static constexpr intmax_t num = type::num; - static constexpr intmax_t den = type::den; + using type = ratio; + static constexpr std::intmax_t num = type::num; + static constexpr std::intmax_t den = type::den; }; } @@ -91,8 +109,8 @@ namespace units { struct ratio_divide { static_assert(R2::num != 0, "division by 0"); using type = ratio_multiply>; - static constexpr intmax_t num = type::num; - static constexpr intmax_t den = type::den; + static constexpr std::intmax_t num = type::num; + static constexpr std::intmax_t den = type::den; }; } @@ -105,8 +123,8 @@ namespace units { // todo: simplified template struct common_ratio { - static constexpr intmax_t gcd_num = std::gcd(R1::num, R2::num); - static constexpr intmax_t gcd_den = std::gcd(R1::den, R2::den); + static constexpr std::intmax_t gcd_num = std::gcd(R1::num, R2::num); + static constexpr std::intmax_t gcd_den = std::gcd(R1::den, R2::den); using type = ratio; };