Solve Linear Congruences Ax = B (mod N) for values of x in range [0, N-1]
Last Updated :
12 Jul, 2021
Given three positive integers A, B, and N, which represent a linear congruence of the form AX=B (mod N), the task is to print all possible values of X (mod N) i.e in the range [0, N-1] that satisfies this equation. If there is no solution, print -1.
Examples:
Input: A=15, B=9, N=18
Output: 15, 3, 9
Explanation: The values of X satisfying the condition AX=B (mod N) are {3, 9, 15}.
(15*15)%18 = 225%18=9
(3*15)%18 = 45%18=9
(9*15)%18 = 135%18=9
Input: A=9, B=21, N=30
Output: 9, 19, 20
Approach: The idea is based on the following observations:
- A solution exists if and only if B is divisible by GCD(A, N) i.e B%GCD(A, N)=0.
- The number of solutions for X (mod N) is GCD(A, N).
Proof:
- Given, AX=B (mod N)
? there exist a number Y such that AX=B+NY
AX-NY=B — (1)
This is a linear Diophantine equation, and is solvable if and only if GCD(A, N) divides B.
- Now, using the Extended Euclidean Algorithm, u and v can be found such that Au+Nv=GCD(A, N)=d(say)
? Au+Nv=d
? Au=d (mod N) — (2)
- Assuming B%d=0, so that solution of Equation 1 exists,
Multiplying both sides of Equation 2 by B/d, (possible since B/d is an integer),
Au*(B/d)=d*(B/d) (mod N) or A*(u*B/d)=B (mod N).
Thus, u*B/d is a solution of Equation 1.
- Let X0 be u*B/d.
Thus, the d solutions of Equation 1 will be X0, X0+(N/d), X0+2*(N/d), …, X0+(d-1)*(N/d)
Follow the steps below to solve the problem:
- Initialize variable d as GCD(A, N) as well as u using the Extended Euclidean Algorithm.
- If B is not divisible by d, print -1 as the result.
- Else iterate in the range [0, d-1] using the variable i and in each iteration print the value of u*(B/d)+i*(N/d).
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
long long ExtendedEuclidAlgo(
long long a, long long b,
long long & x, long long & y)
{
if (b == 0) {
x = 1;
y = 0;
return a;
}
else {
long long x1, y1;
long long gcd
= ExtendedEuclidAlgo(b, a % b, x1, y1);
x = y1;
y = x1 - floor (a / b) * y1;
return gcd;
}
}
void linearCongruence( long long A,
long long B,
long long N)
{
A = A % N;
B = B % N;
long long u = 0, v = 0;
long long d = ExtendedEuclidAlgo(A, N, u, v);
if (B % d != 0) {
cout << -1 << endl;
return ;
}
long long x0 = (u * (B / d)) % N;
if (x0 < 0)
x0 += N;
for ( long long i = 0; i <= d - 1; i++)
cout << (x0 + i * (N / d)) % N << " " ;
}
int main()
{
long long A = 15;
long long B = 9;
long long N = 18;
linearCongruence(A, B, N);
return 0;
}
|
Java
import java.io.*;
class GFG{
public static long [] ExtendedEuclidAlgo( long a,
long b)
{
if (a == 0 )
{
return new long []{b, 0 , 1 };
}
else
{
long x1 = 1 , y1 = 1 ;
long gcdy[] = ExtendedEuclidAlgo(b % a, a);
long gcd = gcdy[ 0 ];
x1 = gcdy[ 1 ];
y1 = gcdy[ 2 ];
long y = x1;
long x = y1 - ( long )Math.floor(b / a) * x1;
return new long [] {gcd, x, y};
}
}
public static void linearCongruence( long A,
long B,
long N)
{
A = A % N;
B = B % N;
long u = 0 , v = 0 ;
long person[] = ExtendedEuclidAlgo(A, N);
long d = person[ 0 ];
u = person[ 1 ];
v = person[ 2 ];
if (B % d != 0 )
{
System.out.println(- 1 );
return ;
}
long x0 = (u * (B / d)) % N;
if (x0 < 0 )
x0 += N;
for ( long i = 0 ; i <= d - 1 ; i++)
{
long an = (x0 + i * (N / d)) % N;
System.out.print(an + " " );
}
}
public static void main(String[] args)
{
long A = 15 ;
long B = 9 ;
long N = 18 ;
linearCongruence(A, B, N);
}
}
|
Python3
def ExtendedEuclidAlgo(a, b):
if a = = 0 :
return b, 0 , 1
gcd, x1, y1 = ExtendedEuclidAlgo(b % a, a)
x = y1 - (b / / a) * x1
y = x1
return gcd, x, y
def linearCongruence(A, B, N):
A = A % N
B = B % N
u = 0
v = 0
d, u, v = ExtendedEuclidAlgo(A, N)
if (B % d ! = 0 ):
print ( - 1 )
return
x0 = (u * (B / / d)) % N
if (x0 < 0 ):
x0 + = N
for i in range (d):
print ((x0 + i * (N / / d)) % N, end = " " )
A = 15
B = 9
N = 18
linearCongruence(A, B, N)
|
C#
using System;
class GFG{
public static long [] ExtendedEuclidAlgo( long a,
long b)
{
if (a == 0)
{
return new long []{b, 0, 1};
}
else
{
long x1 = 1, y1 = 1;
long [] gcdy = ExtendedEuclidAlgo(b % a, a);
long gcd = gcdy[0];
x1 = gcdy[1];
y1 = gcdy[2];
long y = x1;
long x = y1 - ( long )(b / a) * x1;
return new long [] {gcd, x, y};
}
}
public static void linearCongruence( long A,
long B,
long N)
{
A = A % N;
B = B % N;
long u = 0, v = 0;
long []person = ExtendedEuclidAlgo(A, N);
long d = person[0];
u = person[1];
v = person[2];
if (B % d != 0)
{
Console.WriteLine(-1);
return ;
}
long x0 = (u * (B / d)) % N;
if (x0 < 0)
x0 += N;
for ( long i = 0; i <= d - 1; i++)
{
long an = (x0 + i * (N / d)) % N;
Console.Write(an + " " );
}
}
static public void Main (){
long A = 15;
long B = 9;
long N = 18;
linearCongruence(A, B, N);
}
}
|
Javascript
<script>
function ExtendedEuclidAlgo(a, b)
{
if (a == 0)
{
return [b, 0, 1];
}
else
{
let x1 = 1, y1 = 1;
let gcdy = ExtendedEuclidAlgo(b % a, a);
let gcd = gcdy[0];
x1 = gcdy[1];
y1 = gcdy[2];
let y = x1;
let x = y1 - Math.floor(b / a) * x1;
return [gcd, x, y];
}
}
function linearCongruence(A, B, N)
{
A = A % N;
B = B % N;
let u = 0, v = 0;
let person = ExtendedEuclidAlgo(A, N);
let d = person[0];
u = person[1];
v = person[2];
if (B % d != 0)
{
document.write(-1);
return ;
}
let x0 = (u * (B / d)) % N;
if (x0 < 0)
x0 += N;
for (let i = 0; i <= d - 1; i++)
{
let an = (x0 + i * (N / d)) % N;
document.write(an + " " );
}
}
let A = 15;
let B = 9;
let N = 18;
linearCongruence(A, B, N);
</script>
|
Time Complexity: O(log(min(A, N))
Auxiliary Space: O(1)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...