pub trait ModTetration {
    // Required method
    fn mod_tetration(self, b: Self, n: Self) -> Self;
}
Expand description

tetration。

bamodn{}^b a\bmod n を求める。{}^\bullet \bullet は次のように定義される。 ba={1,if b=0;a((b1)a),if b1. {}^b a = \begin{cases} 1, & \text{if } b = 0; \\ a^{\left({}^{(b-1)} a\right)}, & \text{if } b \ge 1. \end{cases} 直感的に書けば、a(a(a))b manymodn\underbrace{a^{(a^{(\cdots ^a)})}}_{b\text{ many}} \bmod n である。

Idea

大変大きくなりうる zz に対して azmodna^z\bmod n を求めることを考える。 このとき、dlogIdea と同じ議論から、ある μ\mu, λ\lambda が存在して z<μz\lt\mu または z=μ+qλ+rz=\mu+q\cdot\lambda+r とでき、後者のとき azaμ+r(modn)a^z\equiv a^{\mu+r}\pmod{n} が成り立つ。

ここで、μlog2(n)\mu\le\log_2(n), λφ(n)\lambda\sqsubseteq\varphi(n) である。 さらに、任意の nn に対して log2(n)φ(n)\log_2(n)\le\varphi(n) なので、zφ(n)z\ge\varphi(n) ならば zμz\ge\mu とわかる。よって、以下のようにできる。 az{az,if z<φ(n);a(zmodφ(n))+φ(n),otherwise. \begin{aligned} a^z \equiv \begin{cases} a^z, & \text{if }z\lt \varphi(n); \\ a^{(z\bmod\varphi(n))+\varphi(n)}, & \text{otherwise}. \end{cases} \end{aligned}

直感的には、指数部が φ(n)\varphi(n) 以上であればすでに周期の中に入っており、入った後は φ(n)\varphi(n) を法として合同かつ φ(n)\varphi(n) 以上の値さえ得られれば十分ということである。

When bb is large

前述のように、bamodn{}^b a\bmod{n} を求める際に b1a{}^{b-1} a を法 φ(n){\varphi(n)} で考える。 その次は φ(φ(n)),φ(φ(φ(n))),\varphi(\varphi(n)), \varphi(\varphi(\varphi(n))), \dots と続く。 φ(n)\varphi^\star(n) 段では考えるべき法が 11 となり、それより上の段のことは無視できる。

そこで、φ(n)\varphi^\star(n) を考える。奇素数 pp に対して φ(pe)=pe1(p1)\varphi(p^e)=p^{e-1}\cdot(p-1) が偶数であることと、φ(2e)=2e1\varphi(2^e)=2^{e-1} であることから、φ(φ(n))<n/2\varphi(\varphi(n))\lt n/2 が成り立つ。すなわち、φ(n)2log(n)\varphi^\star(n)\le 2\log(n) である1

よって、b2log(n)b\ge 2\log(n) であれば b+1aba(modn){}^{b+1} a\equiv {}^b a\pmod{n} となる。

Common bugs

繰り返し二乗法で φ(n)\varphi(n) 以上か判断しつつ azmodφ(n)a^z\bmod\varphi(n) を求める際、 a2a^{2^\bullet}φ(n)\varphi(n) 以上になった時点で azφ(n)a^z\ge\varphi(n) と判断してしまうと、誤検出してしまう場合がある。

fn mod_pow(mut a: u64, mut b: u64, n: u64) -> u64 {
    let mut res = 1 % n;
    let mut large = false;
    while b > 0 {
        if b & 1 == 1 {
            res *= a;
            if res >= n { res %= n; large = true; }
        }
        a *= a;
        if a >= n { a %= n; large = true; } // !
        b >>= 1;
    }
    if large { res + n } else { res }
}

最後のループで初めて a >= n になると、res < n なのに res + n が返ってしまう。 このバグや、あるいはそもそも zφ(n)z\ge\varphi(n) を仮定していることなどにより、 32mod32=0{}^3 2\bmod 32 = 0 としてしまうコードがたくさん提出されている。 \bullet \bullet \bullet \bullet \bullet \bullet \bullet \bullet \bullet \bullet \bullet \bullet

Complexity

O(n)O(\sqrt{n}) time.

律速は、φ(n),φ(φ(n)),\varphi(n), \varphi(\varphi(n)), \dots を求めるパートであり、 O(i=0φ(n)n/2i)=O(n)O(\sum_{i=0}^{\varphi^\star(n)} \sqrt{n/2^i}) = O(\sqrt{n}) である。

Examples

use nekolib::math::ModTetration;

let n = 10_u64.pow(9);

assert_eq!(0_u64.mod_tetration(0, n), 1);
assert_eq!(0_u64.mod_tetration(1, n), 0);
assert_eq!(0_u64.mod_tetration(2, n), 1);
assert_eq!(0_u64.mod_tetration(3, n), 0);

assert_eq!(1_u64.mod_tetration(0, n), 1);
assert_eq!(1_u64.mod_tetration(1, n), 1);

assert_eq!(2_u64.mod_tetration(0, n), 1);
assert_eq!(2_u64.mod_tetration(1, n), 2);
assert_eq!(2_u64.mod_tetration(2, n), 4);
assert_eq!(2_u64.mod_tetration(3, n), 16);
assert_eq!(2_u64.mod_tetration(4, n), 65536);

assert_eq!(3_u64.mod_tetration(9, n), 64_195_387);
assert_eq!(3_u64.mod_tetration(10, n), 464_195_387);
assert_eq!(3_u64.mod_tetration(11, n), 464_195_387);
assert_eq!(3_u64.mod_tetration(99, n), 464_195_387);

Notations

ba{}^b aaba\uparrow\uparrow b (Knuth’s up-arrow notation) や ab2a\to b\to 2 (Conway chained arrow notation) などとも表記される。


  1. ゆるゆるな bound である。実際にはもっと速く減りそう。 

Required Methods§

source

fn mod_tetration(self, b: Self, n: Self) -> Self

Implementations on Foreign Types§

source§

impl ModTetration for u8

source§

fn mod_tetration(self, b: Self, n: Self) -> Self

source§

impl ModTetration for u128

source§

fn mod_tetration(self, b: Self, n: Self) -> Self

source§

impl ModTetration for u64

source§

fn mod_tetration(self, b: Self, n: Self) -> Self

source§

impl ModTetration for u32

source§

fn mod_tetration(self, b: Self, n: Self) -> Self

source§

impl ModTetration for u16

source§

fn mod_tetration(self, b: Self, n: Self) -> Self

source§

impl ModTetration for usize

source§

fn mod_tetration(self, b: Self, n: Self) -> Self

Implementors§