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

Ackermann 関数。

与えられた (a,b,n)(a, b, n) に対して A(a,b)modnA(a, b)\bmod n を返す。 自然数 aa, bb に対して Péter–Ackermann 関数 A(a,b)A(a, b) は次のように定義される。

  • A(0,b)=b+1A(0, b) = b+1,
  • A(a+1,0)=A(a,1)A(a+1,0) = A(a, 1),
  • A(a+1,b+1)=A(a,A(a+1,b))A(a+1, b+1) = A(a, A(a+1, b)).

$\gdef{\hyper}{\operatorname{hyper}}$ 以下の性質が知られている。 $$ a\gt 0 \implies \hyper_a(2, b+3)-3. $$ ただし、$\hyper_a$ は aa 番目のハイパー演算子である。

Idea

a4a\le 4 までは mod_powmod_tetration を用いて簡単に求められる。 mod_tetration と同様に、指数部が十分大きくなると値が一定になるので、それを利用する。

$A(5, b) = \hyper_5(2, b+3)-3 = \underbrace{{}^{{}^{{}^2\cdots} 2} 2}_{b+3\text{ many}} - 3$ となるが、A(5,0)A(5, 0) は現実的な値として求められる。 A(5,0)=2223=423=22223=2243=2163=65533. \begin{aligned} A(5, 0) &= {}^{{}^2 2} 2 - 3 \\ &= {}^4 2 - 3 \\ &= 2^{2^{2^2}} - 3 \\ &= 2^{2^4} - 3 \\ &= 2^{16}-3 = 65533. \end{aligned}

一方で、A(5,1)A(5, 1) は次のようになる。 A(5,1)=22223=6553623=22265536 many3. \begin{aligned} A(5, 1) &= {}^{{}^{{}^2 2} 2} 2 - 3 \\ &= {}^{65536} 2 - 3 \\ &= \underbrace{2^{2^{\cdots^2}}}_{65536\text{ many}}-3. \end{aligned}

ここで mod_tetration の議論を思い出すと、bamodn{}^b a \bmod{n}b2log(n)b\ge 2\log(n) であれば一定値となる。引数の型が u64 である今、bb として意味があるのは高々 2log(264)=1282\log(2^{64}) = 128 程度であり、A(5,1)A(5, 1) はそれを十分に上回る。 すなわち、A(5,1)modn=A(4,2log(n))modnA(5, 1)\bmod n = A(4, 2\log(n))\bmod n として計算してしまってよい1

さらに、A(6,0)=A(5,1)A(6, 0) = A(5, 1) などから、a6a\ge 6 についても同様にでき、次のようにできる。

  • A(0,b)b+1(modn)A(0, b) \equiv b+1 \pmod{n},
  • A(1,b)b+2(modn)A(1, b) \equiv b + 2 \pmod{n},
  • A(2,b)2b+3(modn)A(2, b) \equiv 2b + 3 \pmod{n},
  • A(3,b)2b+33(modn)A(3, b) \equiv 2^{b+3} - 3 \pmod{n},
  • A(4,b)b+323(modn)A(4, b) \equiv {}^{b+3} 2 - 3 \pmod{n},
  • A(5,0)65533(modn)A(5, 0) \equiv 65533 \pmod{n},
  • A(5,b)A(4,2log(n))(modn)A(5, b) \equiv A(4, 2\log(n)) \pmod{n} for b1b\ge 1,
  • A(a,b)A(4,2log(n))(modn)A(a, b) \equiv A(4, 2\log(n)) \pmod{n} for a6a\ge 6.

Complexity

入力時間計算量
a2a\le 2 or (a,b)=(5,0)(a, b) = (5, 0)O(1)O(1)
a=3a=3O(log(b))O(\log(b))
otherwiseO(n)O(\sqrt{n})

Examples

use nekolib::math::ModAckermann;

let n = 10_u64.pow(9);
assert_eq!(2_u64.mod_ackermann(5, n), 13);
assert_eq!(3_u64.mod_ackermann(7, n), 1_021);
assert_eq!(4_u64.mod_ackermann(2, n), 719_156_733);
assert_eq!(4_u64.mod_ackermann(3, n), 437_428_733);
assert_eq!(4_u64.mod_ackermann(8, n), 432_948_733);
assert_eq!(9_u64.mod_ackermann(9, n), 432_948_733);

  1. 32768-bit 整数を受け取るような状況ではよくなさそう。512-word の多倍長整数と思うとそこそこ現実的な気もする? だとしても A(5,2)A(5, 2) はもう現実的じゃなさそう。 

Required Methods§

source

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

Implementations on Foreign Types§

source§

impl ModAckermann for usize

source§

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

source§

impl ModAckermann for u32

source§

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

source§

impl ModAckermann for u16

source§

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

source§

impl ModAckermann for u64

source§

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

source§

impl ModAckermann for u128

source§

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

source§

impl ModAckermann for u8

source§

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

Implementors§