C#中自定义ModPow计算性能优化需求
Hey there! Let's get your custom ModPow function up to speed—since you can't use the built-in BigInteger.ModPow, we can leverage two key strategies: exponentiation by squaring (the same logic powering the built-in method) and split computations (as you suspected) to cut down on runtime. Let's break this down step by step for your test case: 888999000^202404606 % 237291793913.
1. Core Optimization: Exponentiation by Squaring (Binary Exponentiation)
Your slow function is likely using a naive linear approach (multiplying P e times and taking mod each time), which has a time complexity of O(e)—way too slow for e ~ 2e8. Exponentiation by squaring reduces this to O(log₂e) (only ~28 iterations for your exponent), and keeps intermediate values small by taking mod n at every step (critical for avoiding expensive big integer operations).
Here's a C# implementation tailored to your use case:
public static BigInteger CustomModPow(BigInteger p, BigInteger e, BigInteger n) { // Handle edge cases first to skip unnecessary work if (n == 1) return 0; if (e == 0) return 1; if (e == 1) return p % n; BigInteger result = 1; p = p % n; // Reduce base upfront to minimize multiplication size while (e > 0) { // If exponent's least significant bit is 1, multiply result by current base if ((e & 1) == 1) { result = (result * p) % n; } // Square the base and shift exponent right (divide by 2) e = e >> 1; p = (p * p) % n; } return result; }
- Key wins: Every multiplication is followed by
% n, so we never deal with numbers larger thann²(which is way smaller than the naive approach'sP^e). This drastically cuts down on big integer computation time.
2. Split Computation for Parallel Speedups
If you want an extra boost, split the problem using either exponent splitting or the Chinese Remainder Theorem (CRT) to leverage parallel processing:
Option A: Split the Exponent
Break the exponent into two parts: e = e1 + e2. Then:P^e % n = (P^e1 % n) * (P^e2 % n) % n
You can compute P^e1 % n and P^e2 % n in parallel (using Task.Run or similar) since they're independent. For your exponent, try splitting it evenly: e1 = 100000000, e2 = 102404606—run both custom ModPow calls in parallel then combine the results.
Option B: Use Chinese Remainder Theorem (CRT)
If you can factor n into two coprime integers p and q (i.e., n = p * q and gcd(p,q)=1), you can compute the result modulo p and q separately, then combine them with CRT:
- Compute
x = CustomModPow(888999000, 202404606, p) - Compute
y = CustomModPow(888999000, 202404606, q) - Find
zsuch thatz ≡ x mod pandz ≡ y mod q—thiszis your final result.
For your n = 237291793913, first factorize it (you can use trial division or a factorization tool). If it splits into smaller primes, each ModPow computation will be faster (since smaller moduli mean smaller intermediate values), and you can run the two computations in parallel.
3. Quick Additional Tweaks
- Pre-reduce the base: Always start with
p = p % n(we do this in the code above) to make sure your initial base is as small as possible. - Avoid redundant operations: Skip full loop iterations for edge cases like
e=0ore=1. - Use efficient big integer operations: Since you mentioned
BigInteger, the .NET built-in operations are already tuned for performance—no need to reinvent the wheel here.
Testing with Your Data
For your test case, the exponentiation by squaring method alone will handle 888999000^202404606 % 237291793913 in milliseconds, which is a massive improvement over a naive linear approach. If you add parallelism via exponent splitting or CRT, you can shave off even more time on multi-core systems.
内容的提问来源于stack exchange,提问作者Skimo

