crt.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include "crt.h"
  2. #include "egcd.h"
  3. /*Computes the solution to a system of simple linear congruences via the
  4. Chinese Remainder Theorem.
  5. This function solves the system of equations
  6. x = a_i (mod m_i)
  7. A value x satisfies this equation if there exists an integer k such that
  8. x = a_i + k*m_i
  9. Note that under this definition, negative moduli are equivalent to positive
  10. moduli, and a modulus of 0 demands exact equality.
  11. x: Returns the solution, if it exists.
  12. Otherwise, the value is unchanged.
  13. a: An array of the a_i's.
  14. m: An array of the m_i's.
  15. These do not have to be relatively prime.
  16. n: The number of equations in the system.
  17. Return: -1 if the system is not consistent, otherwise the modulus by which
  18. the solution is unique.
  19. This modulus is the LCM of the m_i's, except in the case where one of
  20. them is 0, in which case the return value is also 0.*/
  21. int crt(int *_x,const int _a[],const int _m[],int _n){
  22. int i;
  23. int m0;
  24. int a0;
  25. int x0;
  26. /*If there are no equations, everything is a solution.*/
  27. if(_n<1){
  28. *_x=0;
  29. return 1;
  30. }
  31. /*Start with the first equation.*/
  32. /*Force all moduli to be positive.*/
  33. m0=_m[0]<0?-_m[0]:_m[0];
  34. a0=_a[0];
  35. /*Add in each additional equation, and use it to derive a new, single
  36. equation.*/
  37. for(i=1;i<_n;i++){
  38. int d;
  39. int mi;
  40. int xi;
  41. /*Force all moduli to be positive.*/
  42. mi=_m[i]<0?-_m[i]:_m[i];
  43. /*Compute the inverse of m0 (mod mi) and of mi (mod m0).
  44. These are only inverses if m0 and mi are relatively prime.*/
  45. d=egcd(m0,mi,&xi,&x0);
  46. if(d>1){
  47. /*The hard case: m0 and mi are not relatively prime.*/
  48. /*First: check for consistency.*/
  49. if((a0-_a[i])%d!=0)return -1;
  50. /*If m0 divides mi, the old equation was completely redundant.*/
  51. else if(d==m0){
  52. a0=_a[i];
  53. m0=mi;
  54. }
  55. /*If mi divides m0, the new equation is completely redundant.*/
  56. else if(d!=mi){
  57. /*Otherwise the two have a non-trivial combination.
  58. The system is equivalent to the system
  59. x == a0 (mod m0/d)
  60. x == a0 (mod d)
  61. x == ai (mod mi/d)
  62. x == ai (mod d)
  63. Note that a0+c*(ai-a0) == a0 (mod d) == ai (mod d) for any c, since
  64. d|ai-a0; thus any such c gives solutions that satisfy eqs. 2 and 4.
  65. Choosing c as a multiple of (m0/d) ensures
  66. a0+c*(ai-a0) == a0 (mod m0/d), satisfying eq. 1.
  67. But (m0/d) and (mi/d) are relatively prime, so we can choose
  68. c = (m0/d)*((m0/d)^-1 mod mi/d),
  69. Hence c == 1 (mod mi/d), and
  70. a0+c*(ai-a0) == ai (mod mi/d), satisfying eq. 3.
  71. The inverse of (m0/d) mod (mi/d) can be computed with the egcd().*/
  72. m0/=d;
  73. egcd(m0,mi/d,&xi,&x0);
  74. a0+=(_a[i]-a0)*m0*xi;
  75. m0*=mi;
  76. a0=a0%m0;
  77. }
  78. }
  79. else if(d==1){
  80. /*m0 and mi are relatively prime, so xi and x0 are the inverses of m0 and
  81. mi modulo mi and m0, respectively.
  82. The Chinese Remainder Theorem now states that the solution is given by*/
  83. a0=a0*mi*x0+_a[i]*m0*xi;
  84. /* modulo the LCM of m0 and mi.*/
  85. m0*=mi;
  86. a0%=m0;
  87. }
  88. /*Special case: mi and m0 are both 0.
  89. Check for consistency.*/
  90. else if(a0!=_a[i])return -1;
  91. /*Otherwise, this equation was redundant.*/
  92. }
  93. /*If the final modulus was not 0, then constrain the answer to be
  94. non-negative and less than that modulus.*/
  95. if(m0!=0){
  96. x0=a0%m0;
  97. *_x=x0<0?x0+m0:x0;
  98. }
  99. /*Otherwise, there is only one solution.*/
  100. else *_x=a0;
  101. return m0;
  102. }