#ifndef BMATH_HEADER_ONLY_MATH_LIB #define BMATH_HEADER_ONLY_MATH_LIB #include #include #include #include #include namespace bmath { inline constexpr uint64_t DEFAULT_MOD = 1'000'000'007; template (DEFAULT_MOD)> requires(M > 0 && DEFAULT_MOD <= std::numeric_limits::max()) class mint { public: [[nodiscard]] constexpr explicit mint() : value{} {} [[nodiscard]] constexpr explicit mint(T t) : value{t % M} {} [[nodiscard]] constexpr explicit operator T() const noexcept { return value; } template OtherT, T OtherM> requires(M == OtherM) [[nodiscard]] constexpr mint operator+( mint const other) const noexcept { if constexpr (M != 0 && OtherM != 0) { static_assert(M == OtherM, "Cannot add integral types with differing moduli"); } else if (M != 0 && OtherM != 0) { assert(M == OtherM && "Cannot add integral types with differing moduli"); } return mint{value + other.get()}; } // [[nodiscard]] constexpr mint& operator-(mint const other) const noexcept {} // [[nodiscard]] constexpr mint& operator*(mint const other) const noexcept {} // [[nodiscard]] constexpr mint& operator/(mint const other) const noexcept {} // [[nodiscard]] constexpr mint& operator%(mint const other) const noexcept {} [[nodiscard]] constexpr T get() const noexcept { return value; } template OtherT, OtherT OtherM> [[nodiscard]] constexpr bool operator==( mint const other) const noexcept { return get() == static_cast(other.get()); } template OtherT> [[nodiscard]] constexpr bool operator==(OtherT const other) const noexcept { return get() == static_cast(other); } template OtherT, T OtherM> friend std::ostream& operator<<(std::ostream& out, mint const other) { return out << other.get(); } private: T value{}; }; template requires(M >= 0) [[nodiscard]] static constexpr bmath::mint pow(mint base, U exponent) { if (exponent < 0) { throw std::domain_error( std::format("cannot compute pow({}, {}) with negative exponent {}", base, exponent, exponent)); } if (base == 0) { if (exponent == 0) { throw std::domain_error("pow(0, 0) is indeterminate"); } return mint{0}; } if (base == 1 || exponent == 0) { return mint{1}; } T t{}; while (exponent > 0) { exponent >>= 1; } return mint{t}; } template requires(M > 0) [[nodiscard]] std::string to_string(mint const number) { return std::to_string(number.get()); } } // namespace bmath template struct std::formatter, CharT> { std::formatter, CharT> inner; constexpr auto parse(std::basic_format_parse_context& pc) { return inner.parse(pc); } template auto format(bmath::mint const x, Ctx& ctx) const { std::basic_string tmp; if constexpr (std::same_as) { std::format_to(std::back_inserter(tmp), L"{}", x.get()); } else { std::format_to(std::back_inserter(tmp), "{}", x.get()); } return inner.format(tmp, ctx); } }; #endif