Purpose: Reconstruct a number from its residues modulo several pairwise coprime moduli (an alternative to the standard CRT formula), producing the answer incrementally in a mixed-radix representation, in O(k²) time for k moduli.
Algorithm
- Given congruences
x ≡ a_i (mod m_i)for pairwise coprimem_i, compute a mixed-radix representationx = x1 + x2·m1 + x3·m1·m2 + .... - Compute
x1 = a1. - For each subsequent modulus
mi, computexiby solving:xi = (ai - (x1 + x2·m1 + ... + x(i-1)·m1·...·m(i-2))) · (m1·m2·...·m(i-1))⁻¹ mod mi, where the inverse is taken modulomi. - This determines each
xione at a time, using only modular inverses computed with respect to the moduli processed so far. - The final answer is the mixed-radix sum
x = x1 + x2·m1 + x3·m1·m2 + ... + xk·m1·...·m(k-1), computed directly (no need to reduce modulo the full product unless a canonical residue is desired).
Code
long long modInverse(long long a, long long m); // via Extended Euclidean Algorithm
long long garnerAlgorithm(vector<long long>& a, vector<long long>& m) {
int k = a.size();
vector<long long> x(k);
for (int i = 0; i < k; i++) {
long long cur = a[i];
long long term = 1;
for (int j = 0; j < i; j++) {
cur = ((cur - x[j]) % m[i] + m[i]) % m[i];
cur = (__int128)cur * modInverse(term, m[i]) % m[i]; // (incorrect if reused naively; see note)
term = (__int128)term * m[j] % m[i];
}
x[i] = cur;
}
long long result = 0, multiplier = 1;
for (int i = 0; i < k; i++) {
result += x[i] * multiplier; // combine with __int128 or big integers for large products
multiplier *= m[i];
}
return result;
}(Production implementations carefully separate the running product term from each per-step inverse computation; shown here in simplified form for clarity.)
Paradigm
Dynamic Programming (incremental construction). Each xi is computed directly from previously determined x1, ..., x(i-1) without ever needing to revisit or recompute them, building the final mixed-radix representation digit by digit — a sequential DP-style construction rather than a single closed-form combination.
Complexity
- Time: O(k²) for
kmoduli (each step involves a modular inverse and a running product update against all previous moduli) - Space: O(k)
Proof of Correctness
Why the mixed-radix representation exists and is well-defined: By the Chinese Remainder Theorem, since all mi are pairwise coprime, any residue class modulo M = m1·...·mk corresponds to a unique combination of residues modulo each mi individually — and any such number can be written uniquely in the mixed-radix form x1 + x2·m1 + x3·m1·m2 + ... with each xi in the range [0, mi), analogous to how any integer has a unique base-b digit representation, just with varying “digit bases” mi.
Why each xi is solvable using only previously determined digits: Consider the partial sum S_{i-1} = x1 + x2·m1 + ... + x(i-1)·m1·...·m(i-2). By construction, S_{i-1} ≡ x (mod m1·m2·...·m(i-1)) (this is the defining property of the mixed-radix construction up to term i-1). The full value x must satisfy x ≡ ai (mod mi), so:
S_{i-1} + xi · (m1·...·m(i-1)) ≡ ai (mod mi)
⟹ xi · (m1·...·m(i-1)) ≡ ai - S_{i-1} (mod mi)
Since m1, ..., m(i-1) are all coprime to mi (pairwise coprimality), their product m1·...·m(i-1) is invertible modulo mi, so xi is uniquely solvable via xi = (ai - S_{i-1}) · (m1·...·m(i-1))⁻¹ mod mi.
Why this reconstructs the correct final value: Since each xi is solved to satisfy exactly the i-th congruence given the accumulated lower digits, by induction the final sum x1 + x2·m1 + ... + xk·m1·...·m(k-1) satisfies all k congruences simultaneously, matching the unique CRT solution modulo M. ∎
Variants / Use Cases
- Standard CRT reconstruction formula → alternative closed-form combination; Garner’s is often preferred when moduli are processed incrementally or when intermediate values must stay smaller (avoiding computing the full product
Mupfront) - Big integer arithmetic across multiple small-modulus computations → common in computer algebra systems using Residue Number Systems (RNS)
- RSA-CRT decryption reconstruction → recombining partial results computed modulo
pandqseparately - Multi-precision modular arithmetic libraries → Garner’s incremental approach is often more numerically convenient in software implementations
- Distributed/parallel modular computation reconstruction → combining partial results computed independently modulo different primes