合同式、オイラーの定理
リポジトリ
TODO:
連立線形合同
中国剰余定理
mod_fact
cCk mod p
...
合同式(modular equality)
二つの整数, 自然数について、
なら、
,
()
と書き、がを法(modulus)として合同(congruent)という。
上の性質より、加減乗除を組み合わせた合同演算では、途中にを自由に入れて良い。
実数の範囲では、除算(逆元)について閉じているが、合同演算では閉じていない。
例:
a | :整数aを2進数で表現したときのビット長 |
とすると、上の例の左辺は5|a|の表現長だが、右辺は高々2|a|長の数しか出ない。
法mの下での逆元(inverse element)
法の下での逆元は、拡張ユークリッドの互除法を用いて求めることができる。
はとなるが存在することと同値。
すなわち、となるが.
(すなわち、が互いに素なら逆元が存在する)
/** * Calculates modular multiplicative inverse(a^-1 mod m). * If a^-1 mod m doesn't exist(i.e. a is coprime to m), returns 0.<br> * O( log max(a,m) )<br> * @param a positive integer * @param m modulus * @return a^-1 mod m. 0 -> a^-1 mod m doesn't exist. */ public static final int modInverse(int a, int m){ int[] x = new int[2]; return (extGCD(a, m, x) == 1) ? (x[0] + m) % m : 0; }
オイラー(Euler)関数
自然数に対して、
={a:aとnは互いに素}
とする。
ここで、をオイラーのトーシェント関数(Euler's totient function)(オイラーのφ関数、オイラー関数)という。
相異なる素数に対して、
である。
nの素因数分解を使って、
と表現できるため、
素数が見つかるたび(p-1)/pをかけるだけでオイラー関数の値が求まる。
nの素因数分解はでできるので、も同じオーダーで求められる。
また、エラトステネスの篩の応用でオイラー関数の値のテーブルを作成できる。
//※C++ //オイラーのφ(n)を求める O(√n) //n>0 int euler_phi(int n) { int res = n; for(int i = 2; i*i <= n; ++i){ if(n % i == 0){ res = res / i * (i-1); while(n % i == 0) n/=i; } } if(n != 1) res = res / n * (n-1); return res; } //オイラーのφ(n)の値をテーブルeuler[n]で作成 O(n log log n) //n>0 ※euler.size() == max_n + 1 void euler_phi_table(std::vector<int> &euler, int max_n) { euler.resize(max_n+1); for(int i = 0; i < max_n+1; ++i) euler[i]=i; for(int i = 2; i < max_n+1; ++i){ if(euler[i] == i){ //iは素数 for(int j = i; j < max_n+1; j += i) //jは素数iの倍数 euler[j]=euler[j]/i * (i-1); } } }