28 if (
value >= 0)
return static_cast<uint64_t
>(
value);
29 return static_cast<uint64_t
>(-(
value + 1)) + 1;
33 if (
a <= 0 ||
b <= 0)
return false;
34 if (
static_cast<uint64_t
>(
a) >
35 static_cast<uint64_t
>(std::numeric_limits<int64_t>::max()) /
static_cast<uint64_t
>(
b)) {
59 static_cast<uint64_t
>(std::numeric_limits<int64_t>::max());
60 if (magnitude_a > maximum || magnitude_b > maximum) {
61 throw std::overflow_error(
62 "modular extended_gcd does not support INT64_MIN");
66 int64_t old_r =
static_cast<int64_t
>(magnitude_a);
67 int64_t
r =
static_cast<int64_t
>(magnitude_b);
74 const int64_t quotient = old_r /
r;
75 int64_t temporary =
r;
76 r = old_r - quotient *
r;
80 next_s = old_s - quotient * next_s;
84 next_t = old_t - quotient * next_t;
88 const int64_t result_s =
a < 0 ? -old_s : old_s;
89 const int64_t result_t =
b < 0 ? -old_t : old_t;
102 if (
a == 0)
return b;
103 if (
b == 0)
return a;
104 return lmmp_gcd_11_(
a,
b);
113 return lmmp_is_prime_ulong_(n);
122 return lmmp_next_prime_ulong_(n);
132 throw std::domain_error(
"modular operands must have the same modulus");
147 throw std::domain_error(
"modulus must be positive");
162 const int64_t distance =
mod_ - other.
val_;
178 uint64_t result = lmmp_mulmod_ulong_(
179 static_cast<uint64_t
>(
val_),
180 static_cast<uint64_t
>(other.
val_),
181 static_cast<uint64_t
>(
mod_), &q);
182 return ModInt(
static_cast<int64_t
>(result),
mod_);
187 return *
this * other.
inverse();
202 return !(*
this == other);
213 return other < *
this;
226 throw std::domain_error(
"ModInt::inverse(): zero is not invertible");
231 throw std::domain_error(
232 "ModInt::inverse(): element is not invertible (gcd != 1)");
247 power =
static_cast<uint64_t
>(-(
exp + 1)) + 1;
249 power =
static_cast<uint64_t
>(
exp);
253 if ((power & 1U) != 0) result = result * base;
255 if (power != 0) base = base * base;
266 int64_t r2, int64_t m2,
268 constexpr const char* operation =
"crt";
269 auto step =
context.consume_steps(1, operation);
271 if (m1 <= 0 || m2 <= 0) {
273 "CRT moduli must be positive", operation);
279 "CRT modulus product exceeds int64 range", operation);
287 "CRT moduli must be coprime", operation);
292 const auto merged =
ModInt(r1, product) +
ModInt(m1 * factor, product);
305inline std::pair<int64_t, int64_t>
crt(
306 int64_t r1, int64_t m1, int64_t r2, int64_t m2) {
308 if (merged)
return merged.value();
310 throw std::overflow_error(merged.error().message);
312 throw std::domain_error(merged.error().message);
323inline std::pair<int64_t, int64_t>
multi_crt(
const std::vector<int64_t>& residues,
324 const std::vector<int64_t>& primes) {
325 if (residues.empty() || residues.size() != primes.size()) {
326 throw std::invalid_argument(
"multi_crt(): residues and primes must be non-empty and same size");
329 int64_t modulus = primes[0];
330 int64_t combined =
ModInt(residues[0], modulus).value();
332 for (
size_t i = 1; i < residues.size(); ++i) {
333 auto [x, m] =
crt(combined, modulus, residues[i], primes[i]);
338 return {combined, modulus};
345 const std::vector<int64_t>& primes,
347 constexpr const char* operation =
"multi_crt";
348 auto step =
context.consume_steps(residues.size() + 1, operation);
350 if (residues.empty() || residues.size() != primes.size()) {
353 "multi_crt residues and moduli must be non-empty and the same size",
356 for (int64_t modulus : primes) {
359 "multi_crt moduli must be positive", operation);
363 int64_t modulus = primes[0];
364 int64_t combined =
ModInt(residues[0], modulus).value();
365 for (
size_t i = 1; i < residues.size(); ++i) {
367 if (!merged)
return merged;
368 combined = merged.value().first;
369 modulus = merged.value().second;
376 const std::vector<int64_t>& primes) {
390 constexpr const char* operation =
"rational_reconstruction";
391 auto step =
context.consume_steps(1, operation);
398 "rational reconstruction modulus must be positive",
406 int64_t bound =
static_cast<int64_t
>(
407 std::floor(std::sqrt(
static_cast<double>(m) / 2.0)));
416 step =
context.consume_steps(1, operation);
420 const int64_t quotient = r0 / r1;
421 const int64_t next_r = r0 - quotient * r1;
422 const int64_t next_s = s0 - quotient * s1;
428 int64_t numerator = r1;
431 numerator = -numerator;
434 int64_t unused_s = 0;
435 int64_t unused_t = 0;
436 const bool outside_bound =
437 std::abs(numerator) >= bound ||
denominator == 0 ||
439 const bool not_coprime = !outside_bound &&
441 unused_s, unused_t) != 1;
442 if (outside_bound || not_coprime) {
445 "no rational reconstruction exists in the supported bound",
459 1000000007, 1000000009, 1000000021, 1000000033,
460 1000000087, 1000000093, 1000000097, 1000000103,
461 1000000123, 1000000181, 1000000207, 1000000223,
462 1000000231, 1000000271, 1000000289, 1000000297
473inline bool is_good_prime(int64_t p,
const std::vector<BigInt>& leading_coeffs) {
475 throw std::domain_error(
"prime modulus must be at least two");
477 const BigInt modulus(p);
478 return std::none_of(leading_coeffs.begin(), leading_coeffs.end(),
479 [&modulus](
const BigInt& coefficient) {
480 return (coefficient % modulus).is_zero();
492 int count,
const std::vector<BigInt>& leading_coeffs,
493 uint64_t start_from = UINT64_C(1000000000)) {
495 throw std::invalid_argument(
"prime count must be nonnegative");
497 const auto requested =
static_cast<std::size_t
>(count);
498 const auto maximum =
static_cast<uint64_t
>(std::numeric_limits<int64_t>::max());
499 std::vector<int64_t> result;
500 result.reserve(requested);
501 uint64_t candidate = start_from;
502 while (result.size() < requested) {
503 if (candidate >= maximum) {
504 throw std::overflow_error(
"prime search exceeds the signed residue range");
506 const uint64_t next = lmmp_next_prime_ulong_(candidate);
507 if (next <= candidate || next > maximum) {
508 throw std::overflow_error(
"prime search exhausted the signed residue range");
511 const auto prime =
static_cast<int64_t
>(candidate);
513 result.push_back(
prime);
bool operator!=(const ModInt &other) const
判不等
void require_same_modulus(const ModInt &other) const
bool operator>(const ModInt &other) const
大于比较
bool is_zero() const
判断是否为零
ModInt operator+(const ModInt &other) const
模加法
int64_t modulus() const
获取模数
ModInt inverse() const
求模逆元
ModInt operator-() const
取负
ModInt operator-(const ModInt &other) const
模减法
ModInt operator/(const ModInt &other) const
模除法(乘以逆元)
bool operator==(const ModInt &other) const
判等
ModInt(int64_t v, int64_t p)
构造模整数
int64_t value() const
获取当前值
bool operator<(const ModInt &other) const
小于比较(先比模数,再比值)
static ModInt pow(ModInt base, int64_t exp)
模幂运算
ModInt operator*(const ModInt &other) const
模乘法
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::pair< int64_t, int64_t > value)
bool checked_positive_product(int64_t a, int64_t b, int64_t &out)
uint64_t abs_to_u64(int64_t value)
bool lammp_is_prime(uint64_t n)
判断无符号整数是否为素数
uint64_t lammp_next_prime(uint64_t n)
求大于 n 的下一个素数
ExprResult exp(const ExprPtr &expression, ComputationContext &context)
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::string & v
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
uint64_t lammp_gcd(uint64_t a, uint64_t b)
计算两个无符号整数的最大公约数(调用 LMMP)
CrtResult multi_crt_checked(const std::vector< int64_t > &residues, const std::vector< int64_t > &primes, ComputationContext &context)
Checked CRT for a non-empty list of pairwise coprime positive moduli.
Result< std::pair< int64_t, int64_t > > CrtResult
std::vector< int64_t > generate_good_primes(int count, const std::vector< BigInt > &leading_coeffs, uint64_t start_from=UINT64_C(1000000000))
生成指定数量的好素数
CrtResult crt_checked(int64_t r1, int64_t m1, int64_t r2, int64_t m2, ComputationContext &context)
Checked Chinese remainder theorem for two positive coprime moduli.
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
Result< std::pair< int64_t, int64_t > > RationalReconstructionResult
RationalReconstructionResult rational_reconstruction_checked(int64_t x, int64_t m, ComputationContext &context)
Checked rational reconstruction.
bool is_good_prime(int64_t p, const std::vector< BigInt > &leading_coeffs)
判断素数 p 是否为"好素数"(不整除任何首项系数)
constexpr size_t NUM_MODULAR_PRIMES
预定义素数表的长度
std::pair< int64_t, int64_t > multi_crt(const std::vector< int64_t > &residues, const std::vector< int64_t > &primes)
多模数中国剩余定理
constexpr int64_t MODULAR_PRIMES[]
预定义的大素数表,用于模运算多素数方案
std::pair< int64_t, int64_t > crt(int64_t r1, int64_t m1, int64_t r2, int64_t m2)
中国剩余定理(两模数),返回规范余数与模数乘积。
const std::string const ExprPtr & value
const ExprPtr & denominator
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & t
int64_t extended_gcd(int64_t a, int64_t b, int64_t &s, int64_t &t)
用扩展欧几里得算法求 gcd(a,b) 及 Bezout 系数。