some more changes
This commit is contained in:
parent
36826b9934
commit
12fd46747e
4 changed files with 143 additions and 34 deletions
30
compile_flags.txt
Normal file
30
compile_flags.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
-pedantic-errors
|
||||||
|
-O2
|
||||||
|
-Wall
|
||||||
|
-Wextra
|
||||||
|
-Wpedantic
|
||||||
|
-Wshadow
|
||||||
|
-Wformat=2
|
||||||
|
-Wfloat-equal
|
||||||
|
-Wlogical-op
|
||||||
|
-Wshift-overflow=2
|
||||||
|
-Wnon-virtual-dtor
|
||||||
|
-Wold-style-cast
|
||||||
|
-Wcast-qual
|
||||||
|
-Wuseless-cast
|
||||||
|
-Wno-sign-promotion
|
||||||
|
-Wcast-align
|
||||||
|
-Wunused
|
||||||
|
-Woverloaded-virtual
|
||||||
|
-Wconversion
|
||||||
|
-Wmisleading-indentation
|
||||||
|
-Wduplicated-cond
|
||||||
|
-Wduplicated-branches
|
||||||
|
-Wlogical-op
|
||||||
|
-Wnull-dereference
|
||||||
|
-Wformat=2
|
||||||
|
-Wformat-overflow
|
||||||
|
-Wformat-truncation
|
||||||
|
-Wdouble-promotion
|
||||||
|
-Wundef
|
||||||
|
-DLOCAL
|
||||||
128
include/bmath.hh
128
include/bmath.hh
|
|
@ -1,55 +1,121 @@
|
||||||
#ifndef BMATH_HEADER_ONLY_MATH_LIB
|
#ifndef BMATH_HEADER_ONLY_MATH_LIB
|
||||||
#define BMATH_HEADER_ONLY_MATH_LIB
|
#define BMATH_HEADER_ONLY_MATH_LIB
|
||||||
|
|
||||||
#include <compare>
|
#include <format>
|
||||||
#include <concepts>
|
#include <iterator>
|
||||||
#include <optional>
|
#include <ostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace bmath {
|
namespace bmath {
|
||||||
|
|
||||||
template <std::integral IntegralType, typename Modulus = std::nullopt_t>
|
inline constexpr uint64_t DEFAULT_MOD = 1'000'000'007;
|
||||||
requires(std::integral<Modulus> || std::is_same_v<Modulus, std::nullopt_t>)
|
|
||||||
|
template <std::integral T, T M = static_cast<T>(DEFAULT_MOD)>
|
||||||
|
requires(M > 0 && DEFAULT_MOD <= std::numeric_limits<T>::max())
|
||||||
class mint {
|
class mint {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] constexpr explicit mint() : value{} {}
|
[[nodiscard]] constexpr explicit mint() : value{} {}
|
||||||
[[nodiscard]] constexpr explicit mint(IntegralType _value) : value{_value} {}
|
[[nodiscard]] constexpr explicit mint(T t) : value{t % M} {}
|
||||||
[[nodiscard]] constexpr explicit operator IntegralType() const noexcept {
|
[[nodiscard]] constexpr explicit operator T() const noexcept { return value; }
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename OtherIntegralType, typename OtherModulus>
|
template <std::convertible_to<T> OtherT, T OtherM>
|
||||||
|
requires(M == OtherM)
|
||||||
[[nodiscard]] constexpr mint operator+(
|
[[nodiscard]] constexpr mint operator+(
|
||||||
mint<OtherIntegralType, OtherModulus> const& otherMint) const noexcept {
|
mint<OtherT, OtherM> const other) const noexcept {
|
||||||
return mint{value + otherMint.value};
|
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<T, M>{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 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; }
|
||||||
|
|
||||||
friend constexpr bool operator==(std::convertible_to<IntegralType> auto a,
|
template <std::convertible_to<T> OtherT, OtherT OtherM>
|
||||||
mint const& b) noexcept {
|
|
||||||
return static_cast<IntegralType>(a) == b.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend constexpr bool operator==(
|
|
||||||
mint const& a, std::convertible_to<IntegralType> auto b) noexcept {
|
|
||||||
return a.value == static_cast<IntegralType>(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename OtherIntegralType, typename OtherModulus>
|
|
||||||
[[nodiscard]] constexpr bool operator==(
|
[[nodiscard]] constexpr bool operator==(
|
||||||
mint<OtherIntegralType, OtherModulus> const& otherMint) const noexcept {
|
mint<OtherT, OtherM> const other) const noexcept {
|
||||||
return value == otherMint.value;
|
return get() == static_cast<T>(other.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr IntegralType get() const { return value; }
|
template <std::convertible_to<T> OtherT>
|
||||||
|
[[nodiscard]] constexpr bool operator==(OtherT const other) const noexcept {
|
||||||
|
return get() == static_cast<T>(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::convertible_to<T> OtherT, T OtherM>
|
||||||
|
friend std::ostream& operator<<(std::ostream& out,
|
||||||
|
mint<OtherT, OtherM> const other) {
|
||||||
|
return out << other.get();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IntegralType value{};
|
T value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <std::integral T, T M, std::integral U>
|
||||||
|
requires(M >= 0)
|
||||||
|
[[nodiscard]] static constexpr bmath::mint<T, M> pow(mint<T, M> 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<T, M>{0};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base == 1 || exponent == 0) {
|
||||||
|
return mint<T, M>{1};
|
||||||
|
}
|
||||||
|
|
||||||
|
T t{};
|
||||||
|
|
||||||
|
while (exponent > 0) {
|
||||||
|
exponent >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mint<T, M>{t};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::integral T, T M = DEFAULT_MOD>
|
||||||
|
requires(M > 0)
|
||||||
|
[[nodiscard]] std::string to_string(mint<T, M> const number) {
|
||||||
|
return std::to_string(number.get());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bmath
|
} // namespace bmath
|
||||||
|
|
||||||
|
template <class CharT, std::integral T, T M>
|
||||||
|
struct std::formatter<bmath::mint<T, M>, CharT> {
|
||||||
|
std::formatter<std::basic_string_view<CharT>, CharT> inner;
|
||||||
|
|
||||||
|
constexpr auto parse(std::basic_format_parse_context<CharT>& pc) {
|
||||||
|
return inner.parse(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Ctx>
|
||||||
|
auto format(bmath::mint<T, M> const x, Ctx& ctx) const {
|
||||||
|
std::basic_string<CharT> tmp;
|
||||||
|
if constexpr (std::same_as<CharT, wchar_t>) {
|
||||||
|
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
|
#endif
|
||||||
|
|
|
||||||
2
makefile
2
makefile
|
|
@ -57,6 +57,7 @@ DBG_LDFLAGS := \
|
||||||
-fsanitize=float-cast-overflow
|
-fsanitize=float-cast-overflow
|
||||||
|
|
||||||
CXXFLAGS := $(STD) $(WARNFLAGS) $(INCLUDES) $(BASEDEFS)
|
CXXFLAGS := $(STD) $(WARNFLAGS) $(INCLUDES) $(BASEDEFS)
|
||||||
|
CXXFLAGS += -MMD -MP
|
||||||
ifeq ($(MODE),debug)
|
ifeq ($(MODE),debug)
|
||||||
CXXFLAGS += $(DBGFLAGS)
|
CXXFLAGS += $(DBGFLAGS)
|
||||||
LDFLAGS += $(DBG_LDFLAGS)
|
LDFLAGS += $(DBG_LDFLAGS)
|
||||||
|
|
@ -87,6 +88,7 @@ test: .TEST
|
||||||
$(BUILD_DIR)/$(TEST_DIR)/%.o: $(TEST_DIR)/%.cc
|
$(BUILD_DIR)/$(TEST_DIR)/%.o: $(TEST_DIR)/%.cc
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
-include $(TEST_OBJ:.o=.d)
|
||||||
|
|
||||||
$(TEST_EXE): $(TEST_OBJ)
|
$(TEST_EXE): $(TEST_OBJ)
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "../include/bmath.hh"
|
#include "../include/bmath.hh"
|
||||||
|
|
||||||
using namespace bmath;
|
using namespace bmath;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
constexpr uint64_t four{4}, five{5};
|
constexpr uint64_t four{4}, five{5};
|
||||||
|
|
@ -11,11 +13,20 @@ int main() {
|
||||||
constexpr mint<uint64_t> mintfive{five};
|
constexpr mint<uint64_t> mintfive{five};
|
||||||
|
|
||||||
constexpr auto mintnine = mintfour + mintfive;
|
constexpr auto mintnine = mintfour + mintfive;
|
||||||
static_assert(four + five == mintnine.get());
|
|
||||||
static_assert(mintnine == four + five);
|
static_assert(mintnine == four + five);
|
||||||
|
|
||||||
static_assert(4 + 5 == mint<uint64_t>{9});
|
// static_assert(4 + 5 == mint<uint64_t>{9});
|
||||||
static_assert(mint<uint64_t>{8} == 4 + 3);
|
static_assert(mint<uint64_t, 100000>{8} == 4 + 4);
|
||||||
|
|
||||||
|
static_assert(is_trivially_copyable_v<mint<uint64_t>>);
|
||||||
|
|
||||||
|
pow(mint<int>{2}, 0);
|
||||||
|
|
||||||
|
// cout << (std::format("x: {}\n", mintfour));
|
||||||
|
|
||||||
|
// auto res = mint<int>{4} + mint<int, 5>{4};
|
||||||
|
|
||||||
|
cout << (mint<int, 5>{5} + mint<int, 5>{3});
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue