XLII: Ask anything. Hope this helps.
Notation/definitions:
- Integer x is a
divisor of integer y if and only if there is an integer q such that x*q=y.
- A
prime number is an integer greater than 1 whose only positive divisors are 1 and itself.
- Integers x and y are
coprime if and only if there is no prime number that is a divisor of both x and y (i.e., gcd(x,y)=1).
- phi is
Euler's totient function.
- n is some integer such that n>=2.
- Z_n is the
ring of integers modulo n.
- y is an
inverse of x in Z_n if and only if (x*y)
mod(n)=1.
Lemma: If nonzero element x of Z_n is invertible (i.e., it has an inverse) then the inverse is unique.
proof: If xy=xz=1 (under ring multiplication), then (y)(xy)=(y)(xz)=(y)(1), (yx)y=(yx)z=y, and y=z=y. QED.
Theorem: Nonzero element x of Z_n is invertible if and only if x and n are coprime.
proof:
1) Assume that x and n are coprime. Then, by
Euler's totient theorem, (x*y)mod(n)=1 where y=x^(phi(n)-1), so (y)mod(n) is the unique inverse of x.
2) Assume that x and n are not coprime. Then, there is a prime number p that is a prime factor of both x and n, so that x=p*w and n=p*m for some positive integers w and m. Assume (to the contrary) that y is an inverse of x. Then, there is an integer z such that x*y=z*n+1. Therefore, p*w*y=z*p*m+1, p*(w*y-z*m)=1, and p is a divisor of 1, which is a contradiction.
QED.
Corollary: The number of invertible elements of Z_n equals phi(n).
proof: Zero is never invertible and nonzero x are invertible if and only if x and n are coprime. QED.
Special cases:
a) 1 and n-1 are invertible as themselves in Z_n.
b) If the inverse of x is y, then the inverse of y is x.
c) If n=p where p is prime, then Z_p is a
field, which means that every nonzero element of Z_p is invertible.
CC Code:
Code:
//////////////////////////////////////
//////////////////////////////////////
/*
Language = c++ -ansi -std=c++98 -fno-nonansi-builtins -Werror -Wold-style-cast -pedantic -Wall -W -Wfloat-equal -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wsign-compare
Author = John - CorporalCaptain @ TrekBBS
Date = February 20, 2014
Specification = "OK." means no bugs detected.
Configure min_n and max_n for limits.
Configure do_display switches for miscellaneous info.
Configure do_check switches to perform checks or disable for speed.
*/
//////////////////////////////////////
// switches:
unsigned int min_n = 2; // >= 2
unsigned int max_n = 20; // <= square root of UINT_MAX+1
bool do_display_totient = true;
bool do_check_inverses = true;
bool do_check_non_inverses = true;
//////////////////////////////////////
#include <iostream>
//////////////////////////////////////
unsigned int gcd (unsigned int a, unsigned int b) { // See http://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations
while (b != 0) {
unsigned int t = b;
b = a % b;
a = t;
}
return a;
}
unsigned int totient (unsigned int x) { // See http://en.wikipedia.org/wiki/Euler's_totient_function
unsigned int t = 0;
for (unsigned int j=1; j<=x; j++)
if (gcd(j,x) == 1)
t++;
return t;
}
unsigned int my_exp (unsigned int x, unsigned int y, unsigned int n /* >=2 */) { // (x^y) mod n, by successive squaring
unsigned int x_to_2_to_j = x; // j=0
unsigned int a = 1;
while (y != 0) {
if ((y & 1) == 1) a = (a * x_to_2_to_j /* overflow possible here for large n */) % n;
x_to_2_to_j = (x_to_2_to_j * x_to_2_to_j /* overflow possible here for large n */) % n;
y = y >> 1; // j++
}
return a;
}
//////////////////////////////////////
int main (int argc, char * argv []) {
(void) argc;
(void) argv;
try {
for (unsigned int n=min_n; n<=max_n; n++) {
std::cout << std::endl;
std::cout << "n = " << n << std::endl;
const unsigned int totient_n = totient (n);
if (do_display_totient)
std::cout << "totient = " << totient_n << std::endl;
unsigned int num_invs = 0;
for (unsigned int x=0; x<n; x++) {
////////
std::cout << "x = " << x << " 1/x = ";
bool has_inverse = (gcd(x,n) == 1);
if (has_inverse) {
num_invs++;
unsigned int inv_x = my_exp (x, totient_n-1, n);
std::cout << inv_x;
if (do_check_inverses) {
if (1 != ((x*inv_x)%n))
throw "Bug detected in calculation of inverse";
}
} else {
std::cout << "-";
if (do_check_non_inverses) {
for (unsigned int y=0; y<n; y++)
if (1 == ((x*y)%n))
throw "Bug detected in determination of inverse non-existence";
}
}
////////
std::cout << std::endl;
}
if (totient_n != num_invs)
throw "Bug detected in calculation of number of inverses";
}
std::cout << std::endl;
std::cout << "OK." << std::endl;
}
catch (const char * message) {
std::cerr << "Exception: " << message << "." << std::endl;
}
catch (...) {
std::cerr << "Unknown exception." << std::endl;
}
return 0;
}
//////////////////////////////////////
//////////////////////////////////////
Output:
Code:
n = 2
totient = 1
x = 0 1/x = -
x = 1 1/x = 1
n = 3
totient = 2
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 2
n = 4
totient = 2
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = 3
n = 5
totient = 4
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 3
x = 3 1/x = 2
x = 4 1/x = 4
n = 6
totient = 2
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = -
x = 4 1/x = -
x = 5 1/x = 5
n = 7
totient = 6
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 4
x = 3 1/x = 5
x = 4 1/x = 2
x = 5 1/x = 3
x = 6 1/x = 6
n = 8
totient = 4
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = 3
x = 4 1/x = -
x = 5 1/x = 5
x = 6 1/x = -
x = 7 1/x = 7
n = 9
totient = 6
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 5
x = 3 1/x = -
x = 4 1/x = 7
x = 5 1/x = 2
x = 6 1/x = -
x = 7 1/x = 4
x = 8 1/x = 8
n = 10
totient = 4
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = 7
x = 4 1/x = -
x = 5 1/x = -
x = 6 1/x = -
x = 7 1/x = 3
x = 8 1/x = -
x = 9 1/x = 9
n = 11
totient = 10
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 6
x = 3 1/x = 4
x = 4 1/x = 3
x = 5 1/x = 9
x = 6 1/x = 2
x = 7 1/x = 8
x = 8 1/x = 7
x = 9 1/x = 5
x = 10 1/x = 10
n = 12
totient = 4
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = -
x = 4 1/x = -
x = 5 1/x = 5
x = 6 1/x = -
x = 7 1/x = 7
x = 8 1/x = -
x = 9 1/x = -
x = 10 1/x = -
x = 11 1/x = 11
n = 13
totient = 12
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 7
x = 3 1/x = 9
x = 4 1/x = 10
x = 5 1/x = 8
x = 6 1/x = 11
x = 7 1/x = 2
x = 8 1/x = 5
x = 9 1/x = 3
x = 10 1/x = 4
x = 11 1/x = 6
x = 12 1/x = 12
n = 14
totient = 6
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = 5
x = 4 1/x = -
x = 5 1/x = 3
x = 6 1/x = -
x = 7 1/x = -
x = 8 1/x = -
x = 9 1/x = 11
x = 10 1/x = -
x = 11 1/x = 9
x = 12 1/x = -
x = 13 1/x = 13
n = 15
totient = 8
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 8
x = 3 1/x = -
x = 4 1/x = 4
x = 5 1/x = -
x = 6 1/x = -
x = 7 1/x = 13
x = 8 1/x = 2
x = 9 1/x = -
x = 10 1/x = -
x = 11 1/x = 11
x = 12 1/x = -
x = 13 1/x = 7
x = 14 1/x = 14
n = 16
totient = 8
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = 11
x = 4 1/x = -
x = 5 1/x = 13
x = 6 1/x = -
x = 7 1/x = 7
x = 8 1/x = -
x = 9 1/x = 9
x = 10 1/x = -
x = 11 1/x = 3
x = 12 1/x = -
x = 13 1/x = 5
x = 14 1/x = -
x = 15 1/x = 15
n = 17
totient = 16
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 9
x = 3 1/x = 6
x = 4 1/x = 13
x = 5 1/x = 7
x = 6 1/x = 3
x = 7 1/x = 5
x = 8 1/x = 15
x = 9 1/x = 2
x = 10 1/x = 12
x = 11 1/x = 14
x = 12 1/x = 10
x = 13 1/x = 4
x = 14 1/x = 11
x = 15 1/x = 8
x = 16 1/x = 16
n = 18
totient = 6
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = -
x = 4 1/x = -
x = 5 1/x = 11
x = 6 1/x = -
x = 7 1/x = 13
x = 8 1/x = -
x = 9 1/x = -
x = 10 1/x = -
x = 11 1/x = 5
x = 12 1/x = -
x = 13 1/x = 7
x = 14 1/x = -
x = 15 1/x = -
x = 16 1/x = -
x = 17 1/x = 17
n = 19
totient = 18
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = 10
x = 3 1/x = 13
x = 4 1/x = 5
x = 5 1/x = 4
x = 6 1/x = 16
x = 7 1/x = 11
x = 8 1/x = 12
x = 9 1/x = 17
x = 10 1/x = 2
x = 11 1/x = 7
x = 12 1/x = 8
x = 13 1/x = 3
x = 14 1/x = 15
x = 15 1/x = 14
x = 16 1/x = 6
x = 17 1/x = 9
x = 18 1/x = 18
n = 20
totient = 8
x = 0 1/x = -
x = 1 1/x = 1
x = 2 1/x = -
x = 3 1/x = 7
x = 4 1/x = -
x = 5 1/x = -
x = 6 1/x = -
x = 7 1/x = 3
x = 8 1/x = -
x = 9 1/x = 9
x = 10 1/x = -
x = 11 1/x = 11
x = 12 1/x = -
x = 13 1/x = 17
x = 14 1/x = -
x = 15 1/x = -
x = 16 1/x = -
x = 17 1/x = 13
x = 18 1/x = -
x = 19 1/x = 19
OK.
Tested for:
Code:
unsigned int min_n = 2;
unsigned int max_n = 2000;
bool do_display_totient = true;
bool do_check_inverses = true;
bool do_check_non_inverses = true;