|
8 | 8 | #include <stdint.h> |
9 | 9 | #include <math.h> |
10 | 10 |
|
| 11 | +#ifdef _MSC_VER |
| 12 | +#include <intrin.h> |
| 13 | +#endif |
| 14 | + |
11 | 15 | namespace Math { |
12 | 16 |
|
13 | 17 | template <typename T> |
@@ -147,8 +151,41 @@ template <typename ResultType, typename... Args> |
147 | 151 | return result; |
148 | 152 | } |
149 | 153 |
|
150 | | -[[nodiscard]] inline constexpr uint64_t reduce(uint32_t value, uint32_t range) noexcept { |
| 154 | +[[nodiscard]] inline constexpr uint64_t reduce(uint32_t value, uint32_t range) noexcept |
| 155 | +{ |
151 | 156 | return ((uint64_t)value * (uint64_t)range) >> 32; |
152 | 157 | } |
153 | 158 |
|
| 159 | +inline uint32_t fastmod_u32(uint32_t a, uint64_t M, uint32_t d) noexcept |
| 160 | +{ |
| 161 | + const uint64_t lowbits = M * a; |
| 162 | +#if defined(__SIZEOF_INT128__) // GCC / Clang |
| 163 | + return (uint32_t)(((__uint128_t)lowbits * d) >> 64); |
| 164 | +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) |
| 165 | + return (uint32_t)__umulh(lowbits, d); |
| 166 | +#else // portable: 32-bit targets |
| 167 | + const uint64_t lo = (lowbits & 0xFFFFFFFFull) * d; |
| 168 | + const uint64_t hi = (lowbits >> 32) * d; |
| 169 | + return (uint32_t)((hi + (lo >> 32)) >> 32); |
| 170 | +#endif |
| 171 | +} |
| 172 | + |
| 173 | +inline constexpr uint64_t computeM_u32(uint32_t d) noexcept { |
| 174 | + return UINT64_C(0xFFFFFFFFFFFFFFFF) / d + 1; |
| 175 | +} |
| 176 | + |
| 177 | +class FastMod32 |
| 178 | +{ |
| 179 | + const uint64_t M; |
| 180 | + const uint32_t d; |
| 181 | +public: |
| 182 | + inline constexpr FastMod32(uint32_t divisor) noexcept |
| 183 | + : M(computeM_u32(divisor)), d(divisor) |
| 184 | + {} |
| 185 | + inline uint32_t mod(uint32_t a) const noexcept |
| 186 | + { |
| 187 | + return fastmod_u32(a, M, d); |
| 188 | + } |
| 189 | +}; |
| 190 | + |
154 | 191 | } // namespace Math |
0 commit comments