num/modnum.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <cassert> | ||
| 4 | #include <istream> | ||
| 5 | #include <ostream> | ||
| 6 | #include <cstdint> | ||
| 7 | #include <concepts> | ||
| 8 | #include <limits> | ||
| 9 | #include <type_traits> | ||
| 10 | |||
| 11 | namespace wala { | ||
| 12 | |||
| 13 | 10188753 | template <typename T> T mod_inv_in_range(T a, T m) { | |
| 14 | // assert(0 <= a && a < m); | ||
| 15 | 10188753 | T x = a, y = m; | |
| 16 | // abs coeff of a in x and y (they're always opposite sign) | ||
| 17 | 10188753 | T vx = 1, vy = 0; | |
| 18 | 10188753 | bool swap = false; | |
| 19 |
8/8unsigned int wala::mod_inv_in_range<unsigned int>(unsigned int, unsigned int):
✓ Branch 4 → 3 taken 30947925 times.
✓ Branch 4 → 5 taken 10162902 times.
✓ Branch 10 → 7 taken 82025 times.
✓ Branch 10 → 11 taken 16125 times.
unsigned long wala::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 64324 times.
✓ Branch 10 → 11 taken 9098 times.
|
41297297 | while (x) { |
| 20 | 31108544 | T k = y / x; | |
| 21 | 31108544 | y %= x; | |
| 22 | 31108544 | vy += k * vx; | |
| 23 | 31108544 | std::swap(x, y); | |
| 24 | 31108544 | std::swap(vx, vy); | |
| 25 | 31108544 | swap ^= 1; | |
| 26 | } | ||
| 27 | 10188753 | assert(y == 1); | |
| 28 |
8/8unsigned int wala::mod_inv_in_range<unsigned int>(unsigned int, unsigned int):
✓ Branch 7 → 8 taken 9495547 times.
✓ Branch 7 → 9 taken 667355 times.
✓ Branch 13 → 14 taken 5501 times.
✓ Branch 13 → 15 taken 10624 times.
unsigned long wala::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 5432 times.
✓ Branch 13 → 15 taken 3666 times.
|
10188753 | return swap ? vy : m - vy; |
| 29 | } | ||
| 30 | |||
| 31 | template <typename T> struct extended_gcd_result { | ||
| 32 | T gcd; | ||
| 33 | T coeff_a, coeff_b; | ||
| 34 | }; | ||
| 35 | 2018 | template <typename T> extended_gcd_result<T> extended_gcd(T a, T b) { | |
| 36 | 2018 | T x = a, y = b; | |
| 37 | // coeff of a and b in x and y | ||
| 38 | 2018 | T ax = 1, ay = 0; | |
| 39 | 2018 | T bx = 0, by = 1; | |
| 40 |
2/2✓ Branch 14 → 9 taken 6604 times.
✓ Branch 14 → 15 taken 2018 times.
|
8622 | while (x) { |
| 41 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 6604 times.
|
6604 | T k = y / x; |
| 42 | 6604 | y %= x; | |
| 43 | 6604 | ay -= k * ax; | |
| 44 | 6604 | by -= k * bx; | |
| 45 | 6604 | std::swap(x, y); | |
| 46 | 6604 | std::swap(ax, ay); | |
| 47 | 6604 | std::swap(bx, by); | |
| 48 | } | ||
| 49 | 2018 | return {y, ay, by}; | |
| 50 | } | ||
| 51 | |||
| 52 | ✗ | template <typename T> T mod_inv(T a, T m) { | |
| 53 | ✗ | a %= m; | |
| 54 | ✗ | a = a < 0 ? a + m : a; | |
| 55 | ✗ | return mod_inv_in_range(a, m); | |
| 56 | } | ||
| 57 | |||
| 58 | // Derives the boilerplate operator surface of a number type from its compound | ||
| 59 | // ops, ==, neg(), and inv(). | ||
| 60 | // Bodies are only instantiated on use, so a type may omit some of the | ||
| 61 | // underlying pieces if the corresponding derived ops are never called. | ||
| 62 | template <typename Self> | ||
| 63 | struct num_ops { | ||
| 64 | ✗ | Self operator+ () const { return static_cast<const Self&>(*this); } | |
| 65 | 32392196 | Self operator- () const { return static_cast<const Self&>(*this).neg(); } | |
| 66 | |||
| 67 | ✗ | friend Self operator ++ (Self& a, int) { Self r = a; ++a; return r; } | |
| 68 | ✗ | friend Self operator -- (Self& a, int) { Self r = a; --a; return r; } | |
| 69 | 23745420542 | friend Self operator + (const Self& a, const Self& b) { return Self(a) += b; } | |
| 70 | 23427826403 | friend Self operator - (const Self& a, const Self& b) { return Self(a) -= b; } | |
| 71 | 13721935768 | friend Self operator * (const Self& a, const Self& b) { return Self(a) *= b; } | |
| 72 | 13626853 | friend Self operator / (const Self& a, const Self& b) { return Self(a) /= b; } | |
| 73 | |||
| 74 | 8201 | friend bool operator != (const Self& a, const Self& b) { return !(a == b); } | |
| 75 | |||
| 76 | ✗ | friend Self neg(const Self& a) { return a.neg(); } | |
| 77 | 3375072 | friend Self inv(const Self& a) { return a.inv(); } | |
| 78 | }; | ||
| 79 | |||
| 80 | // Storage and arithmetic for numbers mod Self::MOD, as a reduced | ||
| 81 | // representative v in [0, MOD) of unsigned type V. | ||
| 82 | // The type provides static MOD (of type V), reduce (value -> representative), | ||
| 83 | // and *=; | ||
| 84 | // everything else is derived here, valid for any MOD up to V's full range | ||
| 85 | // (sums and differences are tracked mod 2^bits, so no headroom is needed). | ||
| 86 | // Hooks may be overridden in the type's own body (e.g. a faster += / -=). | ||
| 87 | template <typename Self, typename V> | ||
| 88 | struct mod_ops : num_ops<Self> { | ||
| 89 | static_assert(std::unsigned_integral<V>); | ||
| 90 | V v; | ||
| 91 | |||
| 92 | struct is_reduced_tag {}; | ||
| 93 | |||
| 94 | 4840271106 | mod_ops() : v(0) {} | |
| 95 | 42580949 | mod_ops(V v_, is_reduced_tag) : v(v_) { assert(v < Self::MOD); } | |
| 96 | 1256965914 | template <std::integral I> mod_ops(I x) : v(Self::reduce(x)) {} | |
| 97 | |||
| 98 | 85136675 | static Self from_reduced(V v) { return Self(v, is_reduced_tag{}); } | |
| 99 | |||
| 100 | // A negative value reduces via its nonnegative complement: x = -1 - ~x. | ||
| 101 | 830025633 | static V reduce(std::signed_integral auto x) { | |
| 102 | using U = std::make_unsigned_t<decltype(x)>; | ||
| 103 |
3/6None:
✓ Branch 2 → 3 taken 63329 times.
✓ Branch 2 → 4 taken 413967 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 6169160 times.
unsigned long wala::mod_ops<wala::mod_goldilocks, unsigned long>::reduce<int>(int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 5 not taken.
|
1228841791 | return x < 0 ? V(Self::MOD - 1 - Self::reduce(U(~x))) : Self::reduce(U(x)); |
| 104 | } | ||
| 105 | |||
| 106 | 204326 | explicit operator V() const { return v; } | |
| 107 | 44201176 | std::make_signed_t<V> balanced() const { | |
| 108 |
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.
wala::mod_ops<wala::modnum<1000000007>, unsigned int>::balanced() const:
✓ Branch 6 → 7 taken 24971 times.
✓ Branch 6 → 9 taken 21067 times.
|
44201176 | return std::make_signed_t<V>(Self::MOD-v > v ? v : v - Self::MOD); |
| 109 | } | ||
| 110 | |||
| 111 |
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.
|
4561372 | friend bool operator == (const Self& a, const Self& b) { return a.v == b.v; } |
| 112 |
17/17✓ 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 9088297 times.
✓ Branch 17 → 18 taken 29512950 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 34 → 35 taken 1919469 times.
✓ Branch 35 → 36 taken 1919469 times.
✓ Branch 36 → 37 taken 1359180 times.
✓ Branch 37 → 38 taken 1359180 times.
✓ Branch 40 → 41 taken 1359630 times.
✓ Branch 41 → 42 taken 1359630 times.
|
159722383 | friend std::ostream& operator << (std::ostream& out, const Self& n) { return out << n.v; } |
| 113 | 210008724 | friend std::istream& operator >> (std::istream& in, Self& n) { int64_t v_; in >> v_; n = Self(v_); return in; } | |
| 114 | |||
| 115 | ✗ | Self& operator ++ () { | |
| 116 | ✗ | ++v; | |
| 117 | ✗ | if (v == Self::MOD) v = 0; | |
| 118 | ✗ | return self(); | |
| 119 | } | ||
| 120 | ✗ | Self& operator -- () { | |
| 121 | ✗ | if (v == 0) v = Self::MOD; | |
| 122 | ✗ | --v; | |
| 123 | ✗ | return self(); | |
| 124 | } | ||
| 125 |
16/17wala::mod_ops<wala::modnum<2013265921>, unsigned int>::operator+=(wala::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.
wala::mod_ops<wala::modnum<998244353>, unsigned int>::operator+=(wala::modnum<998244353> const&):
✓ Branch 8 → 9 taken 3067062451 times.
✓ Branch 8 → 10 taken 4443366985 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.
|
24292903485 | Self& operator += (const Self& o) { v = Self::sub_mod_raw(v, Self::MOD - o.v); return self(); } |
| 126 |
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 3156854583 times.
✓ Branch 8 → 10 taken 2686247867 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.
|
16751668963 | Self& operator -= (const Self& o) { v = Self::sub_mod_raw(v, o.v); return self(); } |
| 127 | 6814046 | Self& operator /= (const Self& o) { return self() *= o.inv(); } | |
| 128 | |||
| 129 | // Returns a - b mod MOD, for b in [0, MOD]; wraparound detects the underflow. | ||
| 130 |
48/50✓ Branch 2 → 3 taken 6011068771 times.
✓ Branch 2 → 4 taken 5255072932 times.
✓ Branch 3 → 4 taken 161158 times.
✓ Branch 3 → 5 taken 1486940 times.
✓ Branch 4 → 5 taken 23436729 times.
✓ Branch 4 → 6 taken 23438267 times.
✓ Branch 5 → 6 taken 7406296477 times.
✓ Branch 5 → 7 taken 6393379509 times.
✓ Branch 6 → 7 taken 77802688 times.
✓ Branch 6 → 8 taken 77424247 times.
✓ Branch 7 → 8 taken 12141324 times.
✓ Branch 7 → 9 taken 12141816 times.
✓ Branch 8 → 9 taken 6420600985 times.
✓ Branch 8 → 10 taken 7416283200 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.
|
18435879850 | static V sub_mod_raw(V a, V b) { return a < b ? a - b + Self::MOD : a - b; } |
| 131 | |||
| 132 |
7/10wala::mod_ops<wala::mod_goldilocks, unsigned long>::neg() const:
✓ Branch 4 → 5 taken 668 times.
✗ Branch 4 → 8 not taken.
wala::mod_ops<wala::modnum<1000000007>, unsigned int>::neg() const:
✓ Branch 4 → 5 taken 2085 times.
✗ Branch 4 → 8 not taken.
wala::mod_ops<wala::modnum<2013265921>, unsigned int>::neg() const:
✓ Branch 4 → 5 taken 164 times.
✗ Branch 4 → 8 not taken.
wala::mod_ops<wala::modnum<998244353>, unsigned int>::neg() const:
✓ Branch 2 → 3 taken 28171870 times.
✓ Branch 2 → 4 taken 4214777 times.
✓ Branch 4 → 5 taken 2553 times.
✓ Branch 4 → 8 taken 79 times.
|
32392196 | Self neg() const { return from_reduced(v ? Self::MOD - v : 0); } |
| 133 | 10188753 | Self inv() const { return from_reduced(mod_inv_in_range(v, Self::MOD)); } | |
| 134 | |||
| 135 | private: | ||
| 136 | 8727747 | Self& self() { return static_cast<Self&>(*this); } | |
| 137 | }; | ||
| 138 | |||
| 139 |
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 1648009 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.
|
4762119637 | template <auto MOD_> struct modnum : mod_ops<modnum<MOD_>, std::make_unsigned_t<decltype(MOD_)>> { |
| 140 | using Self = modnum; | ||
| 141 | static_assert(MOD_ > 0, "MOD must be positive"); | ||
| 142 | using V = std::make_unsigned_t<decltype(MOD_)>; | ||
| 143 | static constexpr V MOD = V(MOD_); | ||
| 144 | |||
| 145 | using base = mod_ops<modnum, V>; | ||
| 146 |
45/54✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 6169202 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 224429150 times.
✓ Branch 4 → 5 taken 2644881 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 3304781 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 23567488 times.
✓ Branch 12 → 13 taken 1696 times.
✓ Branch 12 → 14 taken 644060 times.
✓ Branch 13 → 14 taken 3972963 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 26 → 27 taken 1359591 times.
✓ Branch 27 → 28 taken 1359136 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.
|
833823409 | using base::base; |
| 147 | using base::v; | ||
| 148 | using base::reduce; | ||
| 149 | |||
| 150 |
1/1✓ Branch 24 → 25 taken 17 times.
|
433358636 | static V reduce(std::unsigned_integral auto x) { return V(x % MOD); } |
| 151 | |||
| 152 | 22159332 | explicit operator std::make_signed_t<V>() const | |
| 153 | requires (MOD <= V(std::numeric_limits<std::make_signed_t<V>>::max())) | ||
| 154 | { | ||
| 155 |
3/4✓ Branch 3 → 4 taken 220 times.
✗ Branch 3 → 21 not taken.
✓ Branch 106 → 107 taken 17595 times.
✓ Branch 106 → 108 taken 23068 times.
|
22159112 | return std::make_signed_t<V>(v); |
| 156 | } | ||
| 157 | |||
| 158 | 14799095392 | Self& operator *= (const Self& o) { | |
| 159 |
36/39✓ Branch 2 → 3 taken 439584292 times.
✓ Branch 2 → 4 taken 192673200 times.
✓ Branch 5 → 6 taken 2661835292 times.
✓ Branch 5 → 7 taken 3207830920 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 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.
|
14787067489 | if constexpr (sizeof(V) <= 4) v = V(uint64_t(v) * o.v % MOD); |
| 160 | else v = V(__uint128_t(v) * o.v % MOD); | ||
| 161 | 9165676 | return *this; | |
| 162 | } | ||
| 163 | }; | ||
| 164 | |||
| 165 | struct mod_goldilocks : mod_ops<mod_goldilocks, uint64_t> { | ||
| 166 | using Self = mod_goldilocks; | ||
| 167 | static constexpr uint64_t MOD = 0xffffffff00000001ull; | ||
| 168 | static constexpr uint64_t EPS = -MOD; | ||
| 169 | // We have 2^32 is a primitive 6th root of unity. | ||
| 170 | // Note that omega_8 + omega_8^7 == 2^24 - 2^72 == sqrt(2) | ||
| 171 | // We'll pick the root so that 2^24 - 2^72 is our primitive 384th root of unity. | ||
| 172 | static constexpr uint64_t PRIMITIVE_ROOT = 2717; | ||
| 173 | |||
| 174 | using base = mod_ops<mod_goldilocks, uint64_t>; | ||
| 175 |
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.
|
44298111 | using base::base; |
| 176 | using base::reduce; | ||
| 177 |
3/3✓ Branch 6 → 7 taken 166 times.
✓ Branch 6 → 8 taken 16 times.
✓ Branch 6 → 18 taken 20 times.
|
74224918 | mod_goldilocks() = default; |
| 178 | ✗ | 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{}) {} | |
| 179 | ✗ | mod_goldilocks(__uint128_t a) : base(uint64_t(a % MOD), is_reduced_tag{}) {} | |
| 180 | |||
| 181 | // Avoids the division: any uint64_t is within MOD of reduced. | ||
| 182 | 85577 | static uint64_t reduce(std::unsigned_integral auto x) { | |
| 183 | static_assert(sizeof(x) <= 8); | ||
| 184 | 22195150 | uint64_t a = x; | |
| 185 |
1/6None:
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 8240 times.
unsigned long wala::mod_goldilocks::reduce<unsigned int>(unsigned int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
unsigned long wala::mod_goldilocks::reduce<unsigned long>(unsigned long):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
|
8240 | return a >= MOD ? a - MOD : a; |
| 186 | } | ||
| 187 | |||
| 188 | // returns a-b, assuming -MOD <= a-b, e.g. b <= MOD | ||
| 189 | 1574790070 | static uint64_t sub_mod_raw(uint64_t a, uint64_t b) { | |
| 190 | #if defined(__x86_64__) | ||
| 191 | // TODO: We could try to write this using intrinsics, but GCC sometimes produces the wrong code. | ||
| 192 | 1574790070 | uint64_t res_wrapped = a; | |
| 193 | 1574790070 | uint64_t adjustment = b; | |
| 194 | 1574790070 | asm ( | |
| 195 | // AT&T syntax: SRC DST | ||
| 196 | "sub %[y], %[x]\n\t" | ||
| 197 | // Trick from plonky2 implementation: | ||
| 198 | // After sub, flag CF is set iff we underflowed. We want to correct by EPS == 2^32 - 1 iff C is set. | ||
| 199 | // sbb (subtract with borrow) computes DST <- DST - SRC - CF | ||
| 200 | // Thus, we can use the 32-bit form of sbb on a dummy register to load CF ? EPS : 0. | ||
| 201 | // Here, we'll just reuse the original register holding b. | ||
| 202 | "sbb %k[y], %k[y]\n\t" | ||
| 203 | : [x] "+r"(res_wrapped), | ||
| 204 | [y] "+r"(adjustment) | ||
| 205 | : | ||
| 206 | : "cc" | ||
| 207 | ); | ||
| 208 | #else | ||
| 209 | uint64_t res_wrapped = a - b; | ||
| 210 | uint64_t adjustment = (res_wrapped > a) ? EPS : 0; | ||
| 211 | #endif | ||
| 212 | 740705267 | return res_wrapped - adjustment; | |
| 213 | } | ||
| 214 | |||
| 215 | // Reduce lo + 2^64 * mi + 2^96 * hi, where hi <= MOD | ||
| 216 | 834084803 | static uint64_t reduce_u160_raw(uint64_t lo, uint32_t mi, uint64_t hi) { | |
| 217 | // result = lo - hi + EPS * mi | ||
| 218 | // 0 <= lo <= 2^64 - 1 = MOD + EPS - 1 | ||
| 219 | // 0 <= EPS * mi <= (2^32 - 1) * EPS = MOD - 1 - EPS | ||
| 220 | // 0 <= hi <= MOD | ||
| 221 | // -MOD <= lo - hi + EPS * mi <= 2*MOD-2 | ||
| 222 | // so we do have some leeway | ||
| 223 | 834084803 | return sub_mod_raw(sub_mod_raw(lo, hi), MOD-(uint64_t(mi)<<32)+mi); | |
| 224 | } | ||
| 225 | |||
| 226 | 834084803 | static uint64_t reduce_u128_raw(__uint128_t v) { | |
| 227 | 834084803 | uint64_t hi = uint64_t(v >> 64); | |
| 228 | 834084803 | uint64_t lo = uint64_t(v); | |
| 229 | 834084803 | uint32_t hi_hi = uint32_t(hi >> 32); | |
| 230 | 834084803 | uint32_t hi_lo = uint32_t(hi); | |
| 231 | 834084803 | return reduce_u160_raw(lo, hi_lo, hi_hi); | |
| 232 | } | ||
| 233 | |||
| 234 | 821735278 | Self& operator *= (Self o) { | |
| 235 | 821735278 | v = reduce_u128_raw(__uint128_t(v) * __uint128_t(o.v)); | |
| 236 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 22077513 times.
|
821689685 | return *this; |
| 237 | } | ||
| 238 | }; | ||
| 239 | |||
| 240 | 5218 | template <typename T> T power(T a, long long b) { | |
| 241 | 5218 | assert(b >= 0); | |
| 242 |
22/26wala::mod_goldilocks wala::power<wala::mod_goldilocks>(wala::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 6880 times.
✓ Branch 8 → 10 taken 5914 times.
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 11 → 8 taken 12794 times.
✓ Branch 11 → 12 taken 215 times.
wala::modnum<2013265921> wala::power<wala::modnum<2013265921> >(wala::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 972 times.
✓ Branch 8 → 10 taken 2477 times.
✓ Branch 11 → 8 taken 2917 times.
✓ Branch 11 → 12 taken 110 times.
wala::modnum<998244353> wala::power<wala::modnum<998244353> >(wala::modnum<998244353>, long long):
✓ Branch 5 → 6 taken 21879 times.
✓ Branch 5 → 7 taken 51945 times.
✓ Branch 8 → 5 taken 73824 times.
✓ Branch 8 → 9 taken 4894 times.
✓ Branch 8 → 10 taken 4131 times.
✓ Branch 11 → 8 taken 5414 times.
✓ Branch 11 → 12 taken 218 times.
|
140292 | T r = 1; while (b) { if (b & 1) r *= a; b >>= 1; a *= a; } return r; |
| 243 | } | ||
| 244 | |||
| 245 | template <typename tag> struct dynamic_modnum : mod_ops<dynamic_modnum<tag>, uint32_t> { | ||
| 246 | using Self = dynamic_modnum; | ||
| 247 | |||
| 248 | private: | ||
| 249 | inline static uint32_t MOD_ = 0; | ||
| 250 | inline static uint64_t BARRETT_M = 0; | ||
| 251 | |||
| 252 | public: | ||
| 253 | // Make only the const-reference public, to force the use of set_mod | ||
| 254 | static constexpr uint32_t const& MOD = MOD_; | ||
| 255 | |||
| 256 | using base = mod_ops<dynamic_modnum, uint32_t>; | ||
| 257 | using base::base; | ||
| 258 | using base::v; | ||
| 259 | using base::reduce; | ||
| 260 | |||
| 261 | // Barret reduction taken from KACTL: | ||
| 262 | /** | ||
| 263 | * Author: Simon Lindholm | ||
| 264 | * Date: 2020-05-30 | ||
| 265 | * License: CC0 | ||
| 266 | * Source: https://en.wikipedia.org/wiki/Barrett_reduction | ||
| 267 | * Description: Compute $a \% b$ about 5 times faster than usual, where $b$ is constant but not known at compile time. | ||
| 268 | * Returns a value congruent to $a \pmod b$ in the range $[0, 2b)$. | ||
| 269 | * Status: proven correct, stress-tested | ||
| 270 | * Measured as having 4 times lower latency, and 8 times higher throughput, see stress-test. | ||
| 271 | * Details: | ||
| 272 | * More precisely, it can be proven that the result equals 0 only if $a = 0$, | ||
| 273 | * and otherwise lies in $[1, (1 + a/2^64) * b)$. | ||
| 274 | */ | ||
| 275 | ✗ | static void set_mod(int mod) { | |
| 276 | ✗ | assert(mod > 0); | |
| 277 | ✗ | MOD_ = uint32_t(mod); | |
| 278 | ✗ | BARRETT_M = (uint64_t(-1) / MOD); | |
| 279 | } | ||
| 280 | ✗ | static uint32_t barrett_reduce_partial(uint64_t a) { | |
| 281 | ✗ | return uint32_t(a - uint64_t((__uint128_t(BARRETT_M) * a) >> 64) * MOD); | |
| 282 | } | ||
| 283 | ✗ | static uint32_t barrett_reduce(uint64_t a) { | |
| 284 | ✗ | int32_t res = int32_t(barrett_reduce_partial(a) - MOD); | |
| 285 | ✗ | return uint32_t((res < 0) ? res + int32_t(MOD) : res); | |
| 286 | } | ||
| 287 | |||
| 288 | struct mod_reader { | ||
| 289 | ✗ | friend std::istream& operator >> (std::istream& i, mod_reader) { | |
| 290 | ✗ | int mod; i >> mod; | |
| 291 | ✗ | Self::set_mod(mod); | |
| 292 | ✗ | return i; | |
| 293 | } | ||
| 294 | }; | ||
| 295 | ✗ | static mod_reader MOD_READER() { | |
| 296 | ✗ | return mod_reader(); | |
| 297 | } | ||
| 298 | |||
| 299 | ✗ | static uint32_t reduce(std::unsigned_integral auto x) { | |
| 300 | static_assert(sizeof(x) <= 8); | ||
| 301 | ✗ | return barrett_reduce(x); | |
| 302 | } | ||
| 303 | |||
| 304 | ✗ | explicit operator int() const { return int(v); } | |
| 305 | |||
| 306 | ✗ | Self& operator *= (const Self& o) { | |
| 307 | ✗ | v = barrett_reduce(uint64_t(v) * o.v); | |
| 308 | ✗ | return *this; | |
| 309 | } | ||
| 310 | }; | ||
| 311 | |||
| 312 | template <typename T> struct mod_constraint { | ||
| 313 | T v, mod; | ||
| 314 | |||
| 315 | 2127 | friend mod_constraint operator & (mod_constraint a, mod_constraint b) { | |
| 316 |
2/2✓ Branch 2 → 3 taken 1036 times.
✓ Branch 2 → 4 taken 1091 times.
|
2127 | if (a.mod < b.mod) std::swap(a, b); |
| 317 |
2/2✓ Branch 4 → 5 taken 109 times.
✓ Branch 4 → 6 taken 2018 times.
|
2127 | if (b.mod == 1) return a; |
| 318 | |||
| 319 | 2018 | extended_gcd_result<T> egcd = extended_gcd<T>(a.mod, b.mod); | |
| 320 | 2018 | assert(a.v % egcd.gcd == b.v % egcd.gcd); | |
| 321 | |||
| 322 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 2018 times.
|
2018 | T extra = b.v - a.v % b.mod; |
| 323 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 2018 times.
|
2018 | extra /= egcd.gcd; |
| 324 | |||
| 325 | 2018 | extra *= egcd.coeff_a; | |
| 326 |
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; |
| 327 |
2/2✓ Branch 21 → 22 taken 680 times.
✓ Branch 21 → 23 taken 1338 times.
|
2018 | extra += (extra < 0) ? b.mod / egcd.gcd : 0; |
| 328 | |||
| 329 | return mod_constraint{ | ||
| 330 | 2018 | a.v + extra * a.mod, | |
| 331 | 2018 | a.mod * (b.mod / egcd.gcd) | |
| 332 | 2018 | }; | |
| 333 | } | ||
| 334 | }; | ||
| 335 | |||
| 336 | } // namespace wala | ||
| 337 |