32 #ifndef NUMBER_THEORY_H_ 33 #define NUMBER_THEORY_H_ 47 inline std::vector<int> x2contfrac(
double x, idx N, idx cut = 1e5) {
51 throw exception::OutOfRange(
"qpp::x2contfrac()");
54 std::vector<int> result;
56 for (idx i = 0; i < N; ++i) {
58 result.emplace_back(static_cast<int>(std::llround(std::floor(x))));
59 x = 1 / (x - std::floor(x));
62 result.emplace_back(static_cast<int>(std::llround(std::ceil(x))));
63 x = 1 / (x - std::ceil(x));
65 if (!std::isfinite(x) || std::abs(x) > cut)
84 inline double contfrac2x(
const std::vector<int>& cf, idx N = idx(-1)) {
87 throw exception::ZeroSize(
"qpp::contfrac2x()");
90 throw exception::OutOfRange(
"qpp::contfrac2x()");
99 double tmp = 1. / cf[N - 1];
100 for (idx i = N - 2; i != 0; --i) {
101 tmp = 1. / (tmp + cf[i]);
115 inline bigint gcd(bigint a, bigint b) {
118 if (a == 0 && b == 0)
119 throw exception::OutOfRange(
"qpp::gcd()");
122 if (a == 0 || b == 0)
123 return (std::max(std::abs(a), std::abs(b)));
132 return (result > 0) ? result : -result;
142 inline bigint gcd(
const std::vector<bigint>& as) {
146 throw exception::ZeroSize(
"qpp::gcd()");
149 bigint result = as[0];
150 for (idx i = 1; i < as.size(); ++i) {
151 result = gcd(result, as[i]);
154 return (result > 0) ? result : -result;
165 inline bigint lcm(bigint a, bigint b) {
168 if (a == 0 && b == 0)
169 throw exception::OutOfRange(
"qpp::lcm()");
172 bigint result = a * b / gcd(a, b);
174 return (result > 0) ? result : -result;
184 inline bigint lcm(
const std::vector<bigint>& as) {
188 throw exception::ZeroSize(
"qpp::lcm()");
193 if (std::find(std::begin(as), std::end(as), 0) != std::end(as))
194 throw exception::OutOfRange(
"qpp::lcm()");
197 bigint result = as[0];
199 for (idx i = 1; i < as.size(); ++i) {
200 result = lcm(result, as[i]);
203 return (result > 0) ? result : -result;
212 inline std::vector<idx> invperm(
const std::vector<idx>& perm) {
215 if (!internal::check_perm(perm))
216 throw exception::PermInvalid(
"qpp::invperm()");
220 std::vector<idx> result(perm.size());
221 for (idx i = 0; i < perm.size(); ++i)
235 inline std::vector<idx> compperm(
const std::vector<idx>& perm,
236 const std::vector<idx>& sigma) {
239 if (!internal::check_perm(perm))
240 throw exception::PermInvalid(
"qpp::compperm()");
241 if (!internal::check_perm(sigma))
242 throw exception::PermInvalid(
"qpp::compperm()");
243 if (perm.size() != sigma.size())
244 throw exception::PermInvalid(
"qpp::compperm()");
248 std::vector<idx> result(perm.size());
249 for (idx i = 0; i < perm.size(); ++i)
250 result[i] = perm[sigma[i]];
263 inline std::vector<bigint> factors(bigint a) {
269 if (a == 0 || a == 1)
270 throw exception::OutOfRange(
"qpp::factors()");
273 std::vector<bigint> result;
278 result.emplace_back(d);
285 result.emplace_back(a);
304 inline bigint modmul(bigint a, bigint b, bigint p) {
305 using ubigint =
unsigned long long int;
310 throw exception::OutOfRange(
"qpp::modmul()");
313 if (a == 0 || b == 0)
318 bool is_positive =
true;
333 up =
static_cast<ubigint
>(p);
347 if (up > std::numeric_limits<ubigint>::max() / 2u)
370 return is_positive ?
static_cast<bigint
>(res)
371 : static_cast<bigint>(p - res);
387 inline bigint modpow(bigint a, bigint n, bigint p) {
390 if (a < 0 || n < 0 || p < 1)
391 throw exception::OutOfRange(
"qpp::modpow()");
393 if (a == 0 && n == 0)
394 throw exception::OutOfRange(
"qpp::modpow()");
400 if (n == 0 && p == 1)
405 for (; n > 0; n /= 2) {
407 result = modmul(result, a, p) % p;
408 a = modmul(a, a, p) % p;
424 inline std::tuple<bigint, bigint, bigint> egcd(bigint a, bigint b) {
427 if (a == 0 && b == 0)
428 throw exception::OutOfRange(
"qpp::egcd()");
431 bigint m, n, c, q, r;
432 bigint m1 = 0, m2 = 1, n1 = 1, n2 = 0;
435 q = a / b, r = a - q * b;
436 m = m2 - q * m1, n = n2 - q * n1;
438 m2 = m1, m1 = m, n2 = n1, n1 = n;
440 c = a, m = m2, n = n2;
449 return std::make_tuple(m, n, c);
462 inline bigint modinv(bigint a, bigint p) {
465 if (a <= 0 || p <= 0)
466 throw exception::OutOfRange(
"qpp::modinv()");
470 std::tie(x, y, gcd_ap) = egcd(p, a);
473 throw exception::OutOfRange(
"qpp::modinv()");
476 return (y > 0) ? y : y + p;
487 inline bool isprime(bigint p, idx k = 80) {
493 throw exception::OutOfRange(
"qpp::isprime()");
496 if (p == 2 || p == 3)
500 bigint x = rand(2, p - 1);
501 if (modpow(x, p - 1, p) != 1)
508 for (bigint i = p - 1; i % 2 == 0; ++u, i /= 2)
510 r = (p - 1) / static_cast<bigint>(std::llround(std::pow(2, u)));
513 for (idx i = 0; i < k; ++i) {
515 bigint a = rand(2, p - 2);
518 bigint z = modpow(a, r, p);
520 if (z == 1 || z == p - 1)
525 for (idx j = 0; j < static_cast<idx>(u); ++j) {
526 z = (modmul(z, z, p)) % p;
555 inline bigint randprime(bigint a, bigint b, idx N = 1000) {
559 throw exception::OutOfRange(
"qpp::randprime()");
565 bigint candidate = rand(a, b);
566 if (std::abs(candidate) < 2)
568 if (std::abs(candidate) == 2)
572 bigint x = rand(2, candidate - 1);
573 if (modpow(x, candidate - 1, candidate) != 1)
577 if (isprime(candidate))
582 throw exception::CustomException(
"qpp::randprime()",
597 inline std::vector<std::pair<int, int>>
598 convergents(
const std::vector<int>& cf) {
604 throw exception::OutOfRange(
"qpp::convergents()");
606 std::vector<std::pair<int, int>> result(N);
614 result[0] = std::make_pair(a_0, b_0);
618 result[1] = std::make_pair(cf[1] * std::get<0>(result[0]) + a_minus_one,
619 cf[1] * std::get<1>(result[0]) + b_minus_one);
620 for (idx i = 2; i < N; ++i) {
622 cf[i] * std::get<0>(result[i - 1]) + std::get<0>(result[i - 2]);
624 cf[i] * std::get<1>(result[i - 1]) + std::get<1>(result[i - 2]);
644 inline std::vector<std::pair<int, int>> convergents(
double x, idx N) {
649 throw exception::OutOfRange(
"qpp::convergents()");
651 auto cf = x2contfrac(x, N);
655 return convergents(x2contfrac(x, N));
Quantum++ main namespace.
Definition: circuits.h:35