modnum.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <cassert> | ||
| 4 | #include <iostream> | ||
| 5 | #include <cstdint> | ||
| 6 | #include <concepts> | ||
| 7 | #include <limits> | ||
| 8 | #include <type_traits> | ||
| 9 | |||
| 10 | 10187695 | template <typename T> T mod_inv_in_range(T a, T m) { | |
| 11 | // assert(0 <= a && a < m); | ||
| 12 | 10187695 | T x = a, y = m; | |
| 13 | // abs coeff of a in x and y (they're always opposite sign) | ||
| 14 | 10187695 | T vx = 1, vy = 0; | |
| 15 | 10187695 | bool swap = false; | |
| 16 |
8/8unsigned int mod_inv_in_range<unsigned int>(unsigned int, unsigned int):
✓ Branch 4 → 3 taken 30939796 times.
✓ Branch 4 → 5 taken 10162400 times.
✓ Branch 10 → 7 taken 79818 times.
✓ Branch 10 → 11 taken 15804 times.
unsigned long mod_inv_in_range<unsigned long>(unsigned long, unsigned long):
✓ Branch 4 → 3 taken 14270 times.
✓ Branch 4 → 5 taken 628 times.
✓ Branch 10 → 7 taken 63092 times.
✓ Branch 10 → 11 taken 8863 times.
|
41284671 | while (x) { |
| 17 | 31096976 | T k = y / x; | |
| 18 | 31096976 | y %= x; | |
| 19 | 31096976 | vy += k * vx; | |
| 20 | 31096976 | std::swap(x, y); | |
| 21 | 31096976 | std::swap(vx, vy); | |
| 22 | 31096976 | swap ^= 1; | |
| 23 | } | ||
| 24 | 10187695 | assert(y == 1); | |
| 25 |
8/8unsigned int mod_inv_in_range<unsigned int>(unsigned int, unsigned int):
✓ Branch 7 → 8 taken 9495358 times.
✓ Branch 7 → 9 taken 667042 times.
✓ Branch 13 → 14 taken 5426 times.
✓ Branch 13 → 15 taken 10378 times.
unsigned long mod_inv_in_range<unsigned long>(unsigned long, unsigned long):
✓ Branch 7 → 8 taken 476 times.
✓ Branch 7 → 9 taken 152 times.
✓ Branch 13 → 14 taken 5368 times.
✓ Branch 13 → 15 taken 3495 times.
|
10187695 | return swap ? vy : m - vy; |
| 26 | } | ||
| 27 | |||
| 28 | template <typename T> struct extended_gcd_result { | ||
| 29 | T gcd; | ||
| 30 | T coeff_a, coeff_b; | ||
| 31 | }; | ||
| 32 | 2018 | template <typename T> extended_gcd_result<T> extended_gcd(T a, T b) { | |
| 33 | 2018 | T x = a, y = b; | |
| 34 | // coeff of a and b in x and y | ||
| 35 | 2018 | T ax = 1, ay = 0; | |
| 36 | 2018 | T bx = 0, by = 1; | |
| 37 |
2/2✓ Branch 14 → 9 taken 6604 times.
✓ Branch 14 → 15 taken 2018 times.
|
8622 | while (x) { |
| 38 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 6604 times.
|
6604 | T k = y / x; |
| 39 | 6604 | y %= x; | |
| 40 | 6604 | ay -= k * ax; | |
| 41 | 6604 | by -= k * bx; | |
| 42 | 6604 | std::swap(x, y); | |
| 43 | 6604 | std::swap(ax, ay); | |
| 44 | 6604 | std::swap(bx, by); | |
| 45 | } | ||
| 46 | 2018 | return {y, ay, by}; | |
| 47 | } | ||
| 48 | |||
| 49 | ✗ | template <typename T> T mod_inv(T a, T m) { | |
| 50 | ✗ | a %= m; | |
| 51 | ✗ | a = a < 0 ? a + m : a; | |
| 52 | ✗ | return mod_inv_in_range(a, m); | |
| 53 | } | ||
| 54 | |||
| 55 | // Derives the boilerplate operator surface of a number type from its compound | ||
| 56 | // ops, ==, neg(), and inv(). | ||
| 57 | // Bodies are only instantiated on use, so a type may omit some of the | ||
| 58 | // underlying pieces if the corresponding derived ops are never called. | ||
| 59 | template <typename Self> | ||
| 60 | struct num_ops { | ||
| 61 | ✗ | Self operator+ () const { return static_cast<const Self&>(*this); } | |
| 62 | 32391534 | Self operator- () const { return static_cast<const Self&>(*this).neg(); } | |
| 63 | |||
| 64 | ✗ | friend Self operator ++ (Self& a, int) { Self r = a; ++a; return r; } | |
| 65 | ✗ | friend Self operator -- (Self& a, int) { Self r = a; --a; return r; } | |
| 66 | 22912491636 | friend Self operator + (const Self& a, const Self& b) { return Self(a) += b; } | |
| 67 | 22591061507 | friend Self operator - (const Self& a, const Self& b) { return Self(a) -= b; } | |
| 68 | 13700966883 | friend Self operator * (const Self& a, const Self& b) { return Self(a) *= b; } | |
| 69 | 13626853 | friend Self operator / (const Self& a, const Self& b) { return Self(a) /= b; } | |
| 70 | |||
| 71 | 8201 | friend bool operator != (const Self& a, const Self& b) { return !(a == b); } | |
| 72 | |||
| 73 | ✗ | friend Self neg(const Self& a) { return a.neg(); } | |
| 74 | 3374014 | friend Self inv(const Self& a) { return a.inv(); } | |
| 75 | }; | ||
| 76 | |||
| 77 | // Storage and arithmetic for numbers mod Self::MOD, as a reduced | ||
| 78 | // representative v in [0, MOD) of unsigned type V. | ||
| 79 | // The type provides static MOD (of type V), reduce (value -> representative), | ||
| 80 | // and *=; | ||
| 81 | // everything else is derived here, valid for any MOD up to V's full range | ||
| 82 | // (sums and differences are tracked mod 2^bits, so no headroom is needed). | ||
| 83 | // Hooks may be overridden in the type's own body (e.g. a faster += / -=). | ||
| 84 | template <typename Self, typename V> | ||
| 85 | struct mod_ops : num_ops<Self> { | ||
| 86 | static_assert(std::unsigned_integral<V>); | ||
| 87 | V v; | ||
| 88 | |||
| 89 | struct is_reduced_tag {}; | ||
| 90 | |||
| 91 | 4703151036 | mod_ops() : v(0) {} | |
| 92 | 42579229 | mod_ops(V v_, is_reduced_tag) : v(v_) { assert(v < Self::MOD); } | |
| 93 | 1199606183 | template <std::integral I> mod_ops(I x) : v(Self::reduce(x)) {} | |
| 94 | |||
| 95 | 85133791 | static Self from_reduced(V v) { return Self(v, is_reduced_tag{}); } | |
| 96 | |||
| 97 | // A negative value reduces via its nonnegative complement: x = -1 - ~x. | ||
| 98 | 801517218 | static V reduce(std::signed_integral auto x) { | |
| 99 | using U = std::make_unsigned_t<decltype(x)>; | ||
| 100 |
3/6None:
✓ Branch 2 → 3 taken 62110 times.
✓ Branch 2 → 4 taken 406673 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 6169160 times.
unsigned long mod_ops<mod_goldilocks, unsigned long>::reduce<int>(int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 5 not taken.
|
1192064713 | return x < 0 ? V(Self::MOD - 1 - Self::reduce(U(~x))) : Self::reduce(U(x)); |
| 101 | } | ||
| 102 | |||
| 103 | 200688 | explicit operator V() const { return v; } | |
| 104 | 44197652 | std::make_signed_t<V> balanced() const { | |
| 105 |
6/6None:
✓ Branch 2 → 3 taken 11556440 times.
✓ Branch 2 → 4 taken 10521129 times.
✓ Branch 6 → 7 taken 11556440 times.
✓ Branch 6 → 8 taken 10521129 times.
mod_ops<modnum<1000000007>, unsigned int>::balanced() const:
✓ Branch 6 → 7 taken 22904 times.
✓ Branch 6 → 9 taken 19610 times.
|
44197652 | return std::make_signed_t<V>(Self::MOD-v > v ? v : v - Self::MOD); |
| 106 | } | ||
| 107 | |||
| 108 |
10/16✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 42 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 20 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 42 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 20 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 60 times.
✓ Branch 9 → 10 taken 376543 times.
✓ Branch 9 → 11 taken 7894 times.
✓ Branch 13 → 14 taken 3971648 times.
✓ Branch 13 → 15 taken 610 times.
✗ Branch 75 → 76 not taken.
✓ Branch 75 → 77 taken 29 times.
|
4556122 | friend bool operator == (const Self& a, const Self& b) { return a.v == b.v; } |
| 109 |
16/16✓ Branch 11 → 12 taken 16696892 times.
✓ Branch 12 → 13 taken 30644307 times.
✓ Branch 13 → 14 taken 41198909 times.
✓ Branch 14 → 15 taken 27251494 times.
✓ Branch 16 → 17 taken 1878056 times.
✓ Branch 17 → 18 taken 22302709 times.
✓ Branch 18 → 19 taken 43193692 times.
✓ Branch 19 → 20 taken 66934098 times.
✓ Branch 20 → 21 taken 44165059 times.
✓ Branch 22 → 23 taken 644060 times.
✓ Branch 23 → 24 taken 644060 times.
✓ Branch 37 → 38 taken 1919469 times.
✓ Branch 38 → 39 taken 3278649 times.
✓ Branch 39 → 40 taken 1359180 times.
✓ Branch 42 → 43 taken 1359630 times.
✓ Branch 43 → 44 taken 1359630 times.
|
152496947 | friend std::ostream& operator << (std::ostream& out, const Self& n) { return out << n.v; } |
| 110 | 202798445 | friend std::istream& operator >> (std::istream& in, Self& n) { int64_t v_; in >> v_; n = Self(v_); return in; } | |
| 111 | |||
| 112 | ✗ | Self& operator ++ () { | |
| 113 | ✗ | ++v; | |
| 114 | ✗ | if (v == Self::MOD) v = 0; | |
| 115 | ✗ | return self(); | |
| 116 | } | ||
| 117 | ✗ | Self& operator -- () { | |
| 118 | ✗ | if (v == 0) v = Self::MOD; | |
| 119 | ✗ | --v; | |
| 120 | ✗ | return self(); | |
| 121 | } | ||
| 122 |
17/18None:
✓ Branch 37 → 38 taken 1919469 times.
mod_ops<modnum<2013265921>, unsigned int>::operator+=(modnum<2013265921> const&):
✓ Branch 8 → 9 taken 202208976 times.
✓ Branch 8 → 10 taken 290893518 times.
✓ Branch 21 → 22 taken 17321299 times.
✓ Branch 21 → 25 taken 4756214 times.
mod_ops<modnum<998244353>, unsigned int>::operator+=(modnum<998244353> const&):
✓ Branch 8 → 9 taken 2926750909 times.
✓ Branch 8 → 10 taken 4944177003 times.
✓ Branch 11 → 12 taken 10199479 times.
✓ Branch 11 → 13 taken 10195153 times.
✓ Branch 17 → 18 taken 15 times.
✓ Branch 17 → 36 taken 15377153 times.
✓ Branch 31 → 32 taken 15 times.
✓ Branch 60 → 61 taken 116650992 times.
✓ Branch 60 → 62 taken 2417711716 times.
✓ Branch 71 → 72 taken 5116137 times.
✓ Branch 71 → 73 taken 6587158 times.
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 87 taken 11703295 times.
|
19890327890 | Self& operator += (const Self& o) { v = Self::sub_mod_raw(v, Self::MOD - o.v); return self(); } |
| 123 |
27/27✓ Branch 5 → 6 taken 27256182 times.
✓ Branch 5 → 7 taken 19702212 times.
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 8 taken 11 times.
✓ Branch 8 → 9 taken 3082738973 times.
✓ Branch 8 → 10 taken 2612144891 times.
✓ Branch 11 → 12 taken 16255453 times.
✓ Branch 11 → 13 taken 10308309 times.
✓ Branch 16 → 17 taken 2361333077 times.
✓ Branch 16 → 18 taken 2730847960 times.
✓ Branch 19 → 20 taken 2358256427 times.
✓ Branch 19 → 21 taken 2733924610 times.
✓ Branch 22 → 23 taken 2355893560 times.
✓ Branch 22 → 24 taken 2736287477 times.
✓ Branch 25 → 26 taken 2736572239 times.
✓ Branch 25 → 27 taken 2360353732 times.
✓ Branch 25 → 29 taken 17332579 times.
✓ Branch 42 → 43 taken 20396714 times.
✓ Branch 42 → 44 taken 26561680 times.
✓ Branch 45 → 46 taken 25868191 times.
✓ Branch 45 → 47 taken 21090203 times.
✓ Branch 54 → 55 taken 1180798987 times.
✓ Branch 54 → 56 taken 1353563721 times.
✓ Branch 57 → 58 taken 1363580696 times.
✓ Branch 57 → 59 taken 1170782012 times.
✓ Branch 70 → 71 taken 417264 times.
✓ Branch 70 → 72 taken 23046762 times.
|
12553159019 | Self& operator -= (const Self& o) { v = Self::sub_mod_raw(v, o.v); return self(); } |
| 124 | 6814046 | Self& operator /= (const Self& o) { return self() *= o.inv(); } | |
| 125 | |||
| 126 | // Returns a - b mod MOD, for b in [0, MOD]; wraparound detects the underflow. | ||
| 127 |
48/50✓ Branch 2 → 3 taken 6011068771 times.
✓ Branch 2 → 4 taken 5255072932 times.
✓ Branch 3 → 4 taken 161157 times.
✓ Branch 3 → 5 taken 1486935 times.
✓ Branch 4 → 5 taken 23436729 times.
✓ Branch 4 → 6 taken 23438267 times.
✓ Branch 5 → 6 taken 7833249040 times.
✓ Branch 5 → 7 taken 6178706836 times.
✓ Branch 6 → 7 taken 77774034 times.
✓ Branch 6 → 8 taken 77396225 times.
✓ Branch 7 → 8 taken 12141324 times.
✓ Branch 7 → 9 taken 12141816 times.
✓ Branch 8 → 9 taken 6206173833 times.
✓ Branch 8 → 10 taken 7842990242 times.
✓ Branch 9 → 10 taken 46874996 times.
✗ Branch 9 → 11 not taken.
✓ Branch 11 → 12 taken 10199479 times.
✓ Branch 11 → 13 taken 10195153 times.
✓ Branch 13 → 14 taken 2364098538 times.
✓ Branch 13 → 15 taken 2728082499 times.
✓ Branch 14 → 15 taken 7454549 times.
✓ Branch 14 → 16 taken 7922619 times.
✓ Branch 16 → 17 taken 2366906321 times.
✓ Branch 16 → 18 taken 2738087637 times.
✓ Branch 19 → 20 taken 2358256427 times.
✓ Branch 19 → 21 taken 2733924610 times.
✓ Branch 22 → 23 taken 2357413680 times.
✓ Branch 22 → 24 taken 2752088656 times.
✓ Branch 25 → 26 taken 2731827305 times.
✓ Branch 25 → 27 taken 2360353732 times.
✓ Branch 26 → 27 taken 443749 times.
✓ Branch 26 → 28 taken 4301185 times.
✓ Branch 28 → 29 taken 10 times.
✓ Branch 28 → 30 taken 5 times.
✓ Branch 34 → 35 taken 8671485 times.
✓ Branch 34 → 36 taken 14792541 times.
✓ Branch 39 → 40 taken 20507933 times.
✓ Branch 39 → 41 taken 26450461 times.
✓ Branch 42 → 43 taken 20396714 times.
✓ Branch 42 → 44 taken 26561680 times.
✓ Branch 51 → 52 taken 1181502678 times.
✓ Branch 51 → 53 taken 1352860030 times.
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 56 taken 60 times.
✓ Branch 67 → 68 taken 8388294 times.
✓ Branch 67 → 69 taken 15075732 times.
✓ Branch 68 → 69 taken 5116137 times.
✓ Branch 68 → 70 taken 6587158 times.
✓ Branch 82 → 83 taken 5116137 times.
✓ Branch 82 → 84 taken 6587158 times.
|
14175795665 | static V sub_mod_raw(V a, V b) { return a < b ? a - b + Self::MOD : a - b; } |
| 128 | |||
| 129 |
6/8mod_ops<mod_goldilocks, unsigned long>::neg() const:
✓ Branch 4 → 5 taken 340 times.
✗ Branch 4 → 8 not taken.
mod_ops<modnum<1000000007>, unsigned int>::neg() const:
✓ Branch 4 → 5 taken 2085 times.
✗ Branch 4 → 8 not taken.
mod_ops<modnum<998244353>, unsigned int>::neg() const:
✓ Branch 2 → 3 taken 28171870 times.
✓ Branch 2 → 4 taken 4214777 times.
✓ Branch 4 → 5 taken 2383 times.
✓ Branch 4 → 8 taken 79 times.
|
32391534 | Self neg() const { return from_reduced(v ? Self::MOD - v : 0); } |
| 130 | 10187695 | Self inv() const { return from_reduced(mod_inv_in_range(v, Self::MOD)); } | |
| 131 | |||
| 132 | private: | ||
| 133 | 8623364 | Self& self() { return static_cast<Self&>(*this); } | |
| 134 | }; | ||
| 135 | |||
| 136 |
13/15✓ Branch 2 → 3 taken 1326178 times.
✗ Branch 2 → 5 not taken.
✓ Branch 2 → 7 taken 998 times.
✓ Branch 2 → 10 taken 1325939 times.
✓ Branch 6 → 7 taken 1330720 times.
✓ Branch 6 → 8 taken 76 times.
✓ Branch 6 → 18 taken 98 times.
✓ Branch 8 → 9 taken 146 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1648003 times.
✓ Branch 22 → 23 taken 20 times.
✓ Branch 28 → 29 taken 9 times.
✓ Branch 31 → 32 taken 1919469 times.
✓ Branch 51 → 52 taken 1181502678 times.
✓ Branch 51 → 53 taken 1352860030 times.
|
4629824628 | template <auto MOD_> struct modnum : mod_ops<modnum<MOD_>, std::make_unsigned_t<decltype(MOD_)>> { |
| 137 | using Self = modnum; | ||
| 138 | static_assert(MOD_ > 0, "MOD must be positive"); | ||
| 139 | using V = std::make_unsigned_t<decltype(MOD_)>; | ||
| 140 | static constexpr V MOD = V(MOD_); | ||
| 141 | |||
| 142 | using base = mod_ops<modnum, V>; | ||
| 143 |
43/52✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 6169202 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 202798465 times.
✓ Branch 4 → 5 taken 2644805 times.
✓ Branch 4 → 6 taken 42 times.
✓ Branch 5 → 6 taken 28 times.
✓ Branch 5 → 7 taken 6169180 times.
✓ Branch 6 → 7 taken 1325960 times.
✓ Branch 6 → 8 taken 52582799 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 3304743 times.
✓ Branch 8 → 9 taken 8 times.
✓ Branch 9 → 10 taken 376563 times.
✓ Branch 9 → 11 taken 7894 times.
✓ Branch 10 → 11 taken 43 times.
✓ Branch 11 → 12 taken 21097472 times.
✓ Branch 11 → 13 taken 16357285 times.
✓ Branch 12 → 13 taken 1696 times.
✓ Branch 12 → 14 taken 644060 times.
✓ Branch 13 → 14 taken 3972925 times.
✓ Branch 13 → 15 taken 610 times.
✓ Branch 14 → 15 taken 7454549 times.
✓ Branch 14 → 16 taken 7922619 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 22077513 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 590 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 10644437 times.
✓ Branch 18 → 19 taken 10618909 times.
✓ Branch 18 → 20 taken 11458604 times.
✓ Branch 21 → 22 taken 20 times.
✓ Branch 25 → 26 taken 79 times.
✓ Branch 25 → 27 taken 15 times.
✓ Branch 28 → 29 taken 10 times.
✓ Branch 28 → 30 taken 5 times.
✓ Branch 30 → 31 taken 59 times.
✓ Branch 31 → 32 taken 17 times.
✓ Branch 32 → 33 taken 59 times.
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 6587187 times.
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 62 taken 29 times.
✓ Branch 65 → 66 taken 6587158 times.
✓ Branch 65 → 67 taken 5116137 times.
✓ Branch 68 → 69 taken 5116137 times.
✓ Branch 68 → 70 taken 6587158 times.
✗ Branch 75 → 76 not taken.
✓ Branch 75 → 77 taken 29 times.
✓ Branch 82 → 83 taken 5116137 times.
✓ Branch 82 → 84 taken 6587158 times.
|
798096689 | using base::base; |
| 144 | using base::v; | ||
| 145 | using base::reduce; | ||
| 146 | |||
| 147 |
1/1✓ Branch 24 → 25 taken 17 times.
|
404506783 | static V reduce(std::unsigned_integral auto x) { return V(x % MOD); } |
| 148 | |||
| 149 | 22155694 | explicit operator std::make_signed_t<V>() const | |
| 150 | requires (MOD <= V(std::numeric_limits<std::make_signed_t<V>>::max())) | ||
| 151 | { | ||
| 152 |
3/4✓ Branch 3 → 4 taken 220 times.
✗ Branch 3 → 21 not taken.
✓ Branch 106 → 107 taken 16916 times.
✓ Branch 106 → 108 taken 21928 times.
|
22155474 | return std::make_signed_t<V>(v); |
| 153 | } | ||
| 154 | |||
| 155 | 14742095568 | Self& operator *= (const Self& o) { | |
| 156 |
38/41✓ Branch 2 → 3 taken 440546128 times.
✓ Branch 2 → 4 taken 191711364 times.
✓ Branch 5 → 6 taken 2587949461 times.
✓ Branch 5 → 7 taken 3133498165 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 10644437 times.
✓ Branch 8 → 9 taken 15530640 times.
✓ Branch 8 → 10 taken 25673124 times.
✓ Branch 11 → 12 taken 16255453 times.
✓ Branch 11 → 13 taken 10308309 times.
✓ Branch 12 → 13 taken 321979 times.
✓ Branch 12 → 14 taken 322072 times.
✓ Branch 13 → 14 taken 1487405 times.
✓ Branch 13 → 15 taken 160526 times.
✓ Branch 15 → 16 taken 494484 times.
✓ Branch 15 → 17 taken 22687400 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 10644437 times.
✓ Branch 18 → 19 taken 10618909 times.
✓ Branch 18 → 20 taken 11458604 times.
✓ Branch 25 → 26 taken 2731827305 times.
✓ Branch 25 → 27 taken 2360353732 times.
✓ Branch 28 → 29 taken 446296308 times.
✓ Branch 28 → 30 taken 448311263 times.
✓ Branch 34 → 35 taken 960158 times.
✓ Branch 34 → 36 taken 959311 times.
✓ Branch 45 → 46 taken 25868191 times.
✓ Branch 45 → 47 taken 21090203 times.
✓ Branch 49 → 50 taken 3293587 times.
✓ Branch 49 → 52 taken 3293600 times.
✓ Branch 53 → 54 taken 60 times.
✓ Branch 54 → 55 taken 1180798987 times.
✓ Branch 54 → 56 taken 1353563721 times.
✓ Branch 57 → 58 taken 1363580696 times.
✓ Branch 57 → 59 taken 1170782012 times.
✓ Branch 71 → 72 taken 5116137 times.
✓ Branch 71 → 73 taken 6587158 times.
✓ Branch 79 → 80 taken 6587158 times.
✓ Branch 79 → 81 taken 5116137 times.
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 87 taken 11703295 times.
|
14297827921 | if constexpr (sizeof(V) <= 4) v = V(uint64_t(v) * o.v % MOD); |
| 157 | else v = V(__uint128_t(v) * o.v % MOD); | ||
| 158 | 9110614 | return *this; | |
| 159 | } | ||
| 160 | }; | ||
| 161 | |||
| 162 | struct mod_goldilocks : mod_ops<mod_goldilocks, uint64_t> { | ||
| 163 | using Self = mod_goldilocks; | ||
| 164 | static constexpr uint64_t MOD = 0xffffffff00000001ull; | ||
| 165 | static constexpr uint64_t EPS = -MOD; | ||
| 166 | // We have 2^32 is a primitive 6th root of unity. | ||
| 167 | // Note that omega_8 + omega_8^7 == 2^24 - 2^72 == sqrt(2) | ||
| 168 | // We'll pick the root so that 2^24 - 2^72 is our primitive 384th root of unity. | ||
| 169 | static constexpr uint64_t PRIMITIVE_ROOT = 2717; | ||
| 170 | |||
| 171 | using base = mod_ops<mod_goldilocks, uint64_t>; | ||
| 172 |
6/7✓ Branch 4 → 5 taken 96 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 48 times.
✓ Branch 8 → 9 taken 11556440 times.
✓ Branch 8 → 10 taken 10521129 times.
✓ Branch 11 → 12 taken 11556440 times.
✓ Branch 11 → 13 taken 10521129 times.
|
44294161 | using base::base; |
| 173 | using base::reduce; | ||
| 174 |
3/3✓ Branch 6 → 7 taken 166 times.
✓ Branch 6 → 8 taken 16 times.
✓ Branch 6 → 18 taken 20 times.
|
74213843 | mod_goldilocks() = default; |
| 175 | ✗ | mod_goldilocks(__int128_t a) : base(a < 0 ? uint64_t(MOD - 1 - __uint128_t(~a) % MOD) : uint64_t(__uint128_t(a) % MOD), is_reduced_tag{}) {} | |
| 176 | ✗ | mod_goldilocks(__uint128_t a) : base(uint64_t(a % MOD), is_reduced_tag{}) {} | |
| 177 | |||
| 178 | // Avoids the division: any uint64_t is within MOD of reduced. | ||
| 179 | 85523 | static uint64_t reduce(std::unsigned_integral auto x) { | |
| 180 | static_assert(sizeof(x) <= 8); | ||
| 181 | 22192939 | uint64_t a = x; | |
| 182 |
1/6None:
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 7172 times.
unsigned long mod_goldilocks::reduce<unsigned int>(unsigned int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
unsigned long mod_goldilocks::reduce<unsigned long>(unsigned long):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
|
7172 | return a >= MOD ? a - MOD : a; |
| 183 | } | ||
| 184 | |||
| 185 | // returns a-b, assuming -MOD <= a-b, e.g. b <= MOD | ||
| 186 | 1574704951 | static uint64_t sub_mod_raw(uint64_t a, uint64_t b) { | |
| 187 | #if defined(__x86_64__) | ||
| 188 | // TODO: We could try to write this using intrinsics, but GCC sometimes produces the wrong code. | ||
| 189 | 1574704951 | uint64_t res_wrapped = a; | |
| 190 | 1574704951 | uint64_t adjustment = b; | |
| 191 | 1574704951 | asm ( | |
| 192 | // AT&T syntax: SRC DST | ||
| 193 | "sub %[y], %[x]\n\t" | ||
| 194 | // Trick from plonky2 implementation: | ||
| 195 | // After sub, flag CF is set iff we underflowed. We want to correct by EPS == 2^32 - 1 iff C is set. | ||
| 196 | // sbb (subtract with borrow) computes DST <- DST - SRC - CF | ||
| 197 | // Thus, we can use the 32-bit form of sbb on a dummy register to load CF ? EPS : 0. | ||
| 198 | // Here, we'll just reuse the original register holding b. | ||
| 199 | "sbb %k[y], %k[y]\n\t" | ||
| 200 | : [x] "+r"(res_wrapped), | ||
| 201 | [y] "+r"(adjustment) | ||
| 202 | : | ||
| 203 | : "cc" | ||
| 204 | ); | ||
| 205 | #else | ||
| 206 | uint64_t res_wrapped = a - b; | ||
| 207 | uint64_t adjustment = (res_wrapped > a) ? EPS : 0; | ||
| 208 | #endif | ||
| 209 | 740657560 | return res_wrapped - adjustment; | |
| 210 | } | ||
| 211 | |||
| 212 | // Reduce lo + 2^64 * mi + 2^96 * hi, where hi <= MOD | ||
| 213 | 834047391 | static uint64_t reduce_u160_raw(uint64_t lo, uint32_t mi, uint64_t hi) { | |
| 214 | // result = lo - hi + EPS * mi | ||
| 215 | // 0 <= lo <= 2^64 - 1 = MOD + EPS - 1 | ||
| 216 | // 0 <= EPS * mi <= (2^32 - 1) * EPS = MOD - 1 - EPS | ||
| 217 | // 0 <= hi <= MOD | ||
| 218 | // -MOD <= lo - hi + EPS * mi <= 2*MOD-2 | ||
| 219 | // so we do have some leeway | ||
| 220 | 834047391 | return sub_mod_raw(sub_mod_raw(lo, hi), MOD-(uint64_t(mi)<<32)+mi); | |
| 221 | } | ||
| 222 | |||
| 223 | 834047391 | static uint64_t reduce_u128_raw(__uint128_t v) { | |
| 224 | 834047391 | uint64_t hi = uint64_t(v >> 64); | |
| 225 | 834047391 | uint64_t lo = uint64_t(v); | |
| 226 | 834047391 | uint32_t hi_hi = uint32_t(hi >> 32); | |
| 227 | 834047391 | uint32_t hi_lo = uint32_t(hi); | |
| 228 | 834047391 | return reduce_u160_raw(lo, hi_lo, hi_hi); | |
| 229 | } | ||
| 230 | |||
| 231 | 821697866 | Self& operator *= (Self o) { | |
| 232 | 821697866 | v = reduce_u128_raw(__uint128_t(v) * __uint128_t(o.v)); | |
| 233 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 22077513 times.
|
821652273 | return *this; |
| 234 | } | ||
| 235 | }; | ||
| 236 | |||
| 237 | 4746 | template <typename T> T power(T a, long long b) { | |
| 238 | 4746 | assert(b >= 0); | |
| 239 |
22/26mod_goldilocks power<mod_goldilocks>(mod_goldilocks, long long):
✓ Branch 4 → 5 taken 17024 times.
✓ Branch 4 → 6 taken 11545 times.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 4 taken 28569 times.
✓ Branch 7 → 8 taken 532 times.
✓ Branch 8 → 9 taken 5632 times.
✓ Branch 8 → 10 taken 4834 times.
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 11 → 8 taken 10466 times.
✓ Branch 11 → 12 taken 176 times.
modnum<2013265921> power<modnum<2013265921> >(modnum<2013265921>, long long):
✓ Branch 5 → 6 taken 2128 times.
✓ Branch 5 → 7 taken 8885 times.
✓ Branch 8 → 5 taken 11013 times.
✓ Branch 8 → 9 taken 904 times.
✓ Branch 8 → 10 taken 2092 times.
✓ Branch 11 → 8 taken 2464 times.
✓ Branch 11 → 12 taken 93 times.
modnum<998244353> power<modnum<998244353> >(modnum<998244353>, long long):
✓ Branch 5 → 6 taken 19551 times.
✓ Branch 5 → 7 taken 46301 times.
✓ Branch 8 → 5 taken 65852 times.
✓ Branch 8 → 9 taken 4338 times.
✓ Branch 8 → 10 taken 3580 times.
✓ Branch 11 → 8 taken 4695 times.
✓ Branch 11 → 12 taken 190 times.
|
128264 | T r = 1; while (b) { if (b & 1) r *= a; b >>= 1; a *= a; } return r; |
| 240 | } | ||
| 241 | |||
| 242 | template <typename U, typename V> struct pairnum : num_ops<pairnum<U, V>> { | ||
| 243 | using Self = pairnum; | ||
| 244 | U u; | ||
| 245 | V v; | ||
| 246 | |||
| 247 | ✗ | pairnum() : u(0), v(0) {} | |
| 248 | ✗ | pairnum(long long val) : u(val), v(val) {} | |
| 249 | ✗ | pairnum(const U& u_, const V& v_) : u(u_), v(v_) {} | |
| 250 | |||
| 251 | ✗ | friend std::ostream& operator << (std::ostream& out, const Self& n) { return out << '(' << n.u << ',' << ' ' << n.v << ')'; } | |
| 252 | ✗ | friend std::istream& operator >> (std::istream& in, Self& n) { long long val; in >> val; n = Self(val); return in; } | |
| 253 | |||
| 254 | ✗ | friend bool operator == (const Self& a, const Self& b) { return a.u == b.u && a.v == b.v; } | |
| 255 | |||
| 256 | ✗ | Self inv() const { | |
| 257 | ✗ | return Self(u.inv(), v.inv()); | |
| 258 | } | ||
| 259 | ✗ | Self neg() const { | |
| 260 | ✗ | return Self(u.neg(), v.neg()); | |
| 261 | } | ||
| 262 | |||
| 263 | ✗ | Self& operator ++ () { | |
| 264 | ✗ | ++u, ++v; | |
| 265 | ✗ | return *this; | |
| 266 | } | ||
| 267 | ✗ | Self& operator -- () { | |
| 268 | ✗ | --u, --v; | |
| 269 | ✗ | return *this; | |
| 270 | } | ||
| 271 | |||
| 272 | ✗ | Self& operator += (const Self& o) { | |
| 273 | ✗ | u += o.u; | |
| 274 | ✗ | v += o.v; | |
| 275 | ✗ | return *this; | |
| 276 | } | ||
| 277 | ✗ | Self& operator -= (const Self& o) { | |
| 278 | ✗ | u -= o.u; | |
| 279 | ✗ | v -= o.v; | |
| 280 | ✗ | return *this; | |
| 281 | } | ||
| 282 | ✗ | Self& operator *= (const Self& o) { | |
| 283 | ✗ | u *= o.u; | |
| 284 | ✗ | v *= o.v; | |
| 285 | ✗ | return *this; | |
| 286 | } | ||
| 287 | ✗ | Self& operator /= (const Self& o) { | |
| 288 | ✗ | u /= o.u; | |
| 289 | ✗ | v /= o.v; | |
| 290 | ✗ | return *this; | |
| 291 | } | ||
| 292 | }; | ||
| 293 | |||
| 294 | template <typename tag> struct dynamic_modnum : mod_ops<dynamic_modnum<tag>, uint32_t> { | ||
| 295 | using Self = dynamic_modnum; | ||
| 296 | private: | ||
| 297 | inline static uint32_t MOD_ = 0; | ||
| 298 | inline static uint64_t BARRETT_M = 0; | ||
| 299 | |||
| 300 | public: | ||
| 301 | // Make only the const-reference public, to force the use of set_mod | ||
| 302 | static constexpr uint32_t const& MOD = MOD_; | ||
| 303 | |||
| 304 | using base = mod_ops<dynamic_modnum, uint32_t>; | ||
| 305 | using base::base; | ||
| 306 | using base::v; | ||
| 307 | using base::reduce; | ||
| 308 | |||
| 309 | // Barret reduction taken from KACTL: | ||
| 310 | /** | ||
| 311 | * Author: Simon Lindholm | ||
| 312 | * Date: 2020-05-30 | ||
| 313 | * License: CC0 | ||
| 314 | * Source: https://en.wikipedia.org/wiki/Barrett_reduction | ||
| 315 | * Description: Compute $a \% b$ about 5 times faster than usual, where $b$ is constant but not known at compile time. | ||
| 316 | * Returns a value congruent to $a \pmod b$ in the range $[0, 2b)$. | ||
| 317 | * Status: proven correct, stress-tested | ||
| 318 | * Measured as having 4 times lower latency, and 8 times higher throughput, see stress-test. | ||
| 319 | * Details: | ||
| 320 | * More precisely, it can be proven that the result equals 0 only if $a = 0$, | ||
| 321 | * and otherwise lies in $[1, (1 + a/2^64) * b)$. | ||
| 322 | */ | ||
| 323 | ✗ | static void set_mod(int mod) { | |
| 324 | ✗ | assert(mod > 0); | |
| 325 | ✗ | MOD_ = uint32_t(mod); | |
| 326 | ✗ | BARRETT_M = (uint64_t(-1) / MOD); | |
| 327 | } | ||
| 328 | ✗ | static uint32_t barrett_reduce_partial(uint64_t a) { | |
| 329 | ✗ | return uint32_t(a - uint64_t((__uint128_t(BARRETT_M) * a) >> 64) * MOD); | |
| 330 | } | ||
| 331 | ✗ | static uint32_t barrett_reduce(uint64_t a) { | |
| 332 | ✗ | int32_t res = int32_t(barrett_reduce_partial(a) - MOD); | |
| 333 | ✗ | return uint32_t((res < 0) ? res + int32_t(MOD) : res); | |
| 334 | } | ||
| 335 | |||
| 336 | struct mod_reader { | ||
| 337 | ✗ | friend std::istream& operator >> (std::istream& i, mod_reader) { | |
| 338 | ✗ | int mod; i >> mod; | |
| 339 | ✗ | Self::set_mod(mod); | |
| 340 | ✗ | return i; | |
| 341 | } | ||
| 342 | }; | ||
| 343 | ✗ | static mod_reader MOD_READER() { | |
| 344 | ✗ | return mod_reader(); | |
| 345 | } | ||
| 346 | |||
| 347 | ✗ | static uint32_t reduce(std::unsigned_integral auto x) { | |
| 348 | static_assert(sizeof(x) <= 8); | ||
| 349 | ✗ | return barrett_reduce(x); | |
| 350 | } | ||
| 351 | |||
| 352 | ✗ | explicit operator int() const { return int(v); } | |
| 353 | |||
| 354 | ✗ | Self& operator *= (const Self& o) { | |
| 355 | ✗ | v = barrett_reduce(uint64_t(v) * o.v); | |
| 356 | ✗ | return *this; | |
| 357 | } | ||
| 358 | }; | ||
| 359 | |||
| 360 | template <typename T> struct mod_constraint { | ||
| 361 | T v, mod; | ||
| 362 | |||
| 363 | 2127 | friend mod_constraint operator & (mod_constraint a, mod_constraint b) { | |
| 364 |
2/2✓ Branch 2 → 3 taken 1036 times.
✓ Branch 2 → 4 taken 1091 times.
|
2127 | if (a.mod < b.mod) std::swap(a, b); |
| 365 |
2/2✓ Branch 4 → 5 taken 109 times.
✓ Branch 4 → 6 taken 2018 times.
|
2127 | if (b.mod == 1) return a; |
| 366 | |||
| 367 | 2018 | extended_gcd_result<T> egcd = extended_gcd<T>(a.mod, b.mod); | |
| 368 | 2018 | assert(a.v % egcd.gcd == b.v % egcd.gcd); | |
| 369 | |||
| 370 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 2018 times.
|
2018 | T extra = b.v - a.v % b.mod; |
| 371 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 2018 times.
|
2018 | extra /= egcd.gcd; |
| 372 | |||
| 373 | 2018 | extra *= egcd.coeff_a; | |
| 374 |
2/4✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 2018 times.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 2018 times.
|
2018 | extra %= b.mod / egcd.gcd; |
| 375 |
2/2✓ Branch 21 → 22 taken 680 times.
✓ Branch 21 → 23 taken 1338 times.
|
2018 | extra += (extra < 0) ? b.mod / egcd.gcd : 0; |
| 376 | |||
| 377 | return mod_constraint{ | ||
| 378 | 2018 | a.v + extra * a.mod, | |
| 379 | 2018 | a.mod * (b.mod / egcd.gcd) | |
| 380 | 2018 | }; | |
| 381 | } | ||
| 382 | }; | ||
| 383 |