Modular congruence: Difference between revisions
+ |
stub → cleanup (inline external links related Talk:Hat#Links and markup, other formatting) |
||
| Line 1: | Line 1: | ||
{{ | {{cleanup}}{{Glossary}} | ||
Two numbers <tt>a,b</tt> are '''congruent''' modulo a third number <tt>n</tt> if their values are equal when integer multiples of <tt>n</tt> are added or subtracted from them such that they both lie in the range <tt>0<=x<n</tt> (an operation denoted with the <tt>%</tt> symbol).<ref group="n">When either operand is negative, programming languages' implementations differ in convention. Python ensures that the sign of the output matches that of the second input (the 'modulo base'), ie. <tt>0>=x%n>n</tt> if n is negative, to make <tt>x//n*n+x%n=x</tt> hold, because Python's floordiv operator <tt>//</tt> rounds towards <tt>-∞</tt>, whereas C matches the first, ie. <tt>-4%3=-1</tt>, because its integer division operator, <tt>/</tt>, returns integers but rounds towards <tt>0</tt>, this article will use the Python convention for signed modulo.</ref> A function returning the value of <tt>x</tt> modulo <tt>n</tt> is given in most programming languages with the <tt>%</tt> operator (ie. <tt>x%n</tt>), and according to the C specification (followed by languages like Python), modulo has the same precedence as multiplication and division, and expressions involving multiple of the same precedence adjacent without brackets will be evaluated left-to-right.<ref group="n">Without modulo or floordiv (only multiplication and division), this is equivalent to division being evaluated before multiplication, as is taught in schools.</ref> | Two numbers <tt>a,b</tt> are '''congruent''' modulo a third number <tt>n</tt> if their values are equal when integer multiples of <tt>n</tt> are added or subtracted from them such that they both lie in the range <tt>0<=x<n</tt> (an operation denoted with the <tt>%</tt> symbol).<ref group="n">When either operand is negative, programming languages' implementations differ in convention. Python ensures that the sign of the output matches that of the second input (the 'modulo base'), ie. <tt>0>=x%n>n</tt> if n is negative, to make <tt>x//n*n+x%n=x</tt> hold, because Python's floordiv operator <tt>//</tt> rounds towards <tt>-∞</tt>, whereas C matches the first, ie. <tt>-4%3=-1</tt>, because its integer division operator, <tt>/</tt>, returns integers but rounds towards <tt>0</tt>, this article will use the Python convention for signed modulo.</ref> A function returning the value of <tt>x</tt> modulo <tt>n</tt> is given in most programming languages with the <tt>%</tt> operator (ie. <tt>x%n</tt>), and according to the C specification (followed by languages like Python), modulo has the same precedence as multiplication and division, and expressions involving multiple of the same precedence adjacent without brackets will be evaluated left-to-right.<ref group="n">Without modulo or floordiv (only multiplication and division), this is equivalent to division being evaluated before multiplication, as is taught in schools.</ref> | ||
Revision as of 02:16, 9 May 2023
| This article may require cleanup to meet LifeWiki's quality standards. |
Two numbers a,b are congruent modulo a third number n if their values are equal when integer multiples of n are added or subtracted from them such that they both lie in the range 0<=x<n (an operation denoted with the % symbol).[n 1] A function returning the value of x modulo n is given in most programming languages with the % operator (ie. x%n), and according to the C specification (followed by languages like Python), modulo has the same precedence as multiplication and division, and expressions involving multiple of the same precedence adjacent without brackets will be evaluated left-to-right.[n 2]
Such equalities under the modulo operation are denoted as a≡b (mod n). For instance, 5≡8 (mod 3), because both of them (after multiples of 3 are subtracted) evaluate to 2. Alternatively (for integer modulo bases n), x%n is equivalent to taking x's expansion in base n and truncating the digits with greater place value than 1. Modular arithmetic is generally concerned with the behaviour of operations under the modulo operation with a fixed base.
Additional arithmetic rules allow manipulation of expressions involving modulo operations, such as that x*y%n=(x%n)*(y%n)%n, with which many computations involving modulo operators can be evaluated more efficiently than explicitly, such as modular exponentiation, where calculating x**p%n allows you to "unravel" the exponentiation into a series of multiplications, and modulo the result by n with each successive multiplication.
Beginning with integers n and x (such that 0<=x<n) and recursively adding an integer k to x and modulo'ing by n (ie. setting x=(x+k)%n) will cause x's value to oscillate with period n/gcd(n,k) (equivalently lcm(n,k)/k).
For a modulo base n and period p, for there to exist any integers k such that recursive addition of k has period p, p must be a factor of n (meaning n%p=0). These integers k are then the set of those 0<k<p coprime to p, each multiplied by n/p. The number of such values k is then given by phi(p), where phi is Euler's totient function,
A000010.[n 3]
There is no similar such statement about modular integer multiplication by a constant, because unlike addition of a constant, the structure of its mapping is not invariant across all inputs.[n 4] Due to this, similarly to cellular automata in finite planes as functions on the set of states, recursively applying a multiplication will cause integers to eventually enter one of several cycles, upon which the period depends.[n 5] Implementations of modular exponentiation to large powers with small modulo bases can be further optimised by detecting the length of the cycle that an exponentiation process enters and finding the phase that it ends in by taking the remaining exponent (upon entry to the cycle) modulo this length, and using it as the index in the cycle.
Relationship with bitwise operators
In programming, where x,n are integer (as is usually necessary for bitwise operators) and n is known to be a power of 2, because it corresponds with truncating x's n-ary expansion to the last digit, and its binary expansion to the last log_2(n) digits, x%n=x&n-1, the latter of which can be more efficient to compute. The Stanford bit-twiddling hacks explain division by 1 less than a power of 2.
Notable congruences
These provide algebraic reduction steps for forms that can arise generally in modular arithmetic problems.
- Fermat's little theorem states that for a prime p and other integer c, c**p≡c (mod p).
- Wilson's theorem states that for an integer n, (n-1)! ≡ -1 (mod n).
See also
- Pólya enumeration theorem (through application of a corollary of which, the theorems above can be proven)
Notes
- ↑ When either operand is negative, programming languages' implementations differ in convention. Python ensures that the sign of the output matches that of the second input (the 'modulo base'), ie. 0>=x%n>n if n is negative, to make x//n*n+x%n=x hold, because Python's floordiv operator // rounds towards -∞, whereas C matches the first, ie. -4%3=-1, because its integer division operator, /, returns integers but rounds towards 0, this article will use the Python convention for signed modulo.
- ↑ Without modulo or floordiv (only multiplication and division), this is equivalent to division being evaluated before multiplication, as is taught in schools.
- ↑ These can be tabulated by running print((lambda m: (lambda f: '\n'.join(map(lambda n: 'n='+f(m,n)+': (\n '+',\n '.join(map(lambda p: p[1],filter(lambda p: p[0],map(lambda p: (lambda t: (len(t),'p='+f(m,p)+': ('+','.join(map(str,t))+')'))(tuple(filter(lambda k: n//__import__('math').gcd(n,k)==p,range(n)))),range(1,n+1)))))+')',range(m))))(lambda n,k: ' '*(len(str(n))-len(str(k)))+str(k)))(16)) in the Python terminal. The lengths of the tuples, over all values of p (instead of only nonzero ones), is the triangular array
A054522.
- ↑ Also, it is neither injective (such that all numbers 0<=x<n produce unique values under multiplication by k followed by modulo by n) nor surjective (such that for given n,k every value y can have an x found such that k*x%n=y). An injective function with a range of outputs equal to that of its inputs (like modular addition of a constant) is also surjective, and together they are bijective, meaning an inverse function can be defined. Modular multiplicative inverses (ie. a number y such that x*y%n=1) can be defined where x and n are coprime, and is implemented in Python's three-argument pow function.
- ↑ An equivalent program to the previous one (for the cycle obtained by beginning at x=1) is print((lambda m: (lambda f: '\n'.join(map(lambda n: 'n='+f(m,n)+': ('+','.join((lambda t: map(lambda p: f(m,t.count(p)),range(1,n)))(tuple(map(lambda k: (lambda f: f(f))(lambda f: lambda r,t: (lambda r: t.index(r)+1 if r in t else f(f)(r,(r,)+t))(k*r%n))(1,()),range(1,n)))))+')',range(1,m))))(lambda n,k: ' '*(len(str(n))-len(str(k)))+str(k)))(16)), which generates
A057593,
and the number of cycles counting by print((lambda m: (lambda f: '\n'.join(map(lambda n: 'n='+f(m,n)+': '+','.join(map(lambda k: f(m,(lambda f: f(f))(lambda f: lambda c,i,o,p: (lambda o: o if all(c) else f(f)(c,c.index(0),o,p+1))(o+(c[i]==p)) if c[i] else f(f)(c[:i]+(p,)+c[i+1:],k*i%n,o,p))((0,)*n,0,0,1)),range(n+1))),range(1,m))))(lambda n,k: ' '*(len(str(n))-len(str(k)))+str(k)))(24)) (removing the k=0 column returns
A348888, which has a nice diagram showing the cycles formed by different n,k).
Further reading
- Conway's Game of Life: Mathematics and Construction, Appendix A.1 Modular Congruence
- Combinatorics I, the first chapter of Adam P. Goucher's book, Mathematical Olympiad Dark Arts (that explains a great deal more about modular arithmetic than this)