{
  "id": "P083",
  "slug": "clock-arithmetic",
  "key": "P083-clock-arithmetic",
  "title": "Clock arithmetic",
  "summary": "Working modulo m: powers by repeated squaring step by step, inverses by the extended Euclidean algorithm, the Chinese remainder theorem for moduli that need not be coprime, and the Fermat and Miller-Rabin tests - where Carmichael numbers fool the first.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P083 - Clock arithmetic\n\nWorking modulo m. Powers by repeated squaring, shown step by step;\ninverses by the extended Euclidean algorithm; the Chinese remainder\ntheorem; and the Fermat and Miller-Rabin primality tests, where the\nCarmichael numbers fool the first and not the second.\n\n- `main.eml` - the menu, reading numbers, and the reports\n- `modular.eml` - exact halving and division, modular powers, the\n  extended Euclidean algorithm, inverses, the Chinese remainder theorem,\n  and the two tests\n\nHow each part works:\n\n- Numbers go up to 10^18, past 2^53, so nothing goes through a float:\n  halving and division are long division, digit by digit, and a % m is\n  exact at any size.\n- Powers, as in the corpus case `modular-exponentiation`: go through the\n  exponent's bits from the lowest, square the base each time and multiply\n  it in for each 1 bit, reducing mod m every step. That is one squaring\n  per bit, with every value below m. Done directly, 7^1000 would have 846\n  digits.\n- Inverse: the extended Euclidean algorithm finds x and y with\n  a x + m y = gcd(a, m). When the gcd is 1, x is the inverse of a mod m;\n  otherwise there is none.\n- Chinese remainders: conditions are combined two at a time. Moduli that\n  share a factor are allowed, and when two conditions disagree on that\n  shared part, there is no answer at all.\n- Fermat's test: a prime n has a^(n-1) = 1 (mod n) for every a it does\n  not divide. Carmichael numbers such as 561 pass it for every such a.\n- Miller-Rabin: write n - 1 = 2^s x d with d odd. For a prime, a^d is 1,\n  or one of its squarings is n - 1. 561 fails that for a = 2. A few\n  composites pass it for some bases (3215031751 for 2, 3, 5 and 7), so the\n  verdict uses the first 13 primes as bases, which is known to be exact\n  below 3.3 x 10^24 - far past the 10^18 the program accepts.\n\nWhat is checked: menu choices 1 to 5; numbers from 0 (or 1, or 2) to\n10^18; for the Chinese remainder theorem, 2 to 4 remainders and as many\nmoduli from 2 to 1,000,000. An empty answer cancels.\n\nSessions: `sessions/basic.in` gives:\n- 7^1000 mod 13 step by step, and 2^(10^12) mod 1000000007;\n- the inverses of 17 mod 3120 (2753) and of 3 mod 1000000007;\n- x = 23 (mod 105) from three conditions, and 53 (mod 210) from four;\n- 561 (a Carmichael number), the primes 1000000007 and\n  999999999999999989, and 3215031751, which fools both tests for base 2\n  and is caught by base 11.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- a base of abc and of 10^18 + 1, an exponent of -1, a modulus of 1;\n- 6 mod 9, which has no inverse;\n- one and five remainders; one modulus for two remainders, a modulus over\n  a million; and 1 mod 4 with 2 mod 6, which contradict each other;\n- 1, and the even number 4.\n\nBuilt on the verified corpus case `modular-exponentiation` (repeated\nsquaring, never holding a value above the modulus squared).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P083 clock arithmetic: powers modulo m step by step, inverses by the\n# extended Euclidean algorithm, the Chinese remainder theorem, and the\n# Fermat and Miller-Rabin primality tests - where the Carmichael numbers\n# fool the first and not the second.\nimport modular\n\ndef trim(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef whole(s):\n    # A whole number of up to 18 digits, or -1.\n    if len(s) == 0 or len(s) > 18:\n        return -1\n    0 => n\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef ask(prompt, low, high):\n    while True:\n        trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \")) => a\n        if a == \"\":\n            return -1\n        whole(a) => n\n        if n >= low and n <= high:\n            return n\n        (\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\") ^0\n\ndef numbers(s):\n    [] => out\n    \"\" => w\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if w != \"\":\n                whole(w) => v\n                if v < 0:\n                    return []\n                out + [v] => out\n            \"\" => w\n        else:\n            w + c => w\n    return out\n\ndef lpad(s, n):\n    while len(s) < n:\n        \" \" + s => s\n    return s\n\ndef pow_mod():\n    ask(\"base\", 0, 1000000000000000000) => a\n    if a == -1:\n        \"Cancelled.\" ^0\n        return\n    ask(\"exponent\", 0, 1000000000000000000) => e\n    if e == -1:\n        \"Cancelled.\" ^0\n        return\n    ask(\"modulus\", 2, 1000000000000000000) => m\n    if m == -1:\n        \"Cancelled.\" ^0\n        return\n    modular.power(a, e, m) => r\n    if len(r[1]) <= 20:\n        \"  bit  base (squared each step)        result so far\" ^0\n        for st in r[1]:\n            (\"  \" + lpad(str(st[0]), 3) + \"  \" + lpad(str(st[1]), 24) + \"  \" + lpad(str(st[2]), 19)) ^0\n    (str(a) + \"^\" + str(e) + \" mod \" + str(m) + \" = \" + str(r[0])) ^0\n    (\"One squaring for each of the exponent's \" + str(len(r[1])) + \" bits, every value kept below the modulus, instead of multiplying \" + str(e) + \" times.\") ^0\n\ndef inverse():\n    ask(\"number\", 1, 1000000000000000000) => a\n    if a == -1:\n        \"Cancelled.\" ^0\n        return\n    ask(\"modulus\", 2, 1000000000000000000) => m\n    if m == -1:\n        \"Cancelled.\" ^0\n        return\n    modular.extended(a % m, m) => e\n    if len(e[3]) <= 20:\n        for row in e[3]:\n            (\"  \" + str(row[0]) + \" = \" + str(row[2]) + \" x \" + str(row[1]) + \" + \" + str(row[0] - row[2] * row[1])) ^0\n    if e[0] != 1:\n        (str(a) + \" has no inverse modulo \" + str(m) + \": they share the factor \" + str(e[0]) + \".\") ^0\n        return\n    modular.inverse(a, m) => x\n    (\"Working back up the divisions: \" + str(a) + \" x \" + str(x) + \" = 1 (mod \" + str(m) + \"), so the inverse is \" + str(x) + \".\") ^0\n\ndef remainders():\n    while True:\n        trim(input(\"remainders (2 to 4, like 2 3 2)> \")) => s\n        if s == \"\":\n            \"Cancelled.\" ^0\n            return\n        numbers(s) => rs\n        if len(rs) >= 2 and len(rs) <= 4:\n            while True:\n                trim(input(\"moduli, as many, each 2 to 1000000 (like 3 5 7)> \")) => t\n                if t == \"\":\n                    \"Cancelled.\" ^0\n                    return\n                numbers(t) => ms\n                True => ok\n                for m in ms:\n                    if m < 2 or m > 1000000:\n                        False => ok\n                if ok and len(ms) == len(rs):\n                    \"\" => line\n                    for i in [0:len(ms) - 1]:\n                        if line != \"\":\n                            line + \", \" => line\n                        line + \"x = \" + str(rs[i]) + \" (mod \" + str(ms[i]) + \")\" => line\n                    line ^0\n                    modular.crt(rs, ms) => r\n                    if len(r) == 0:\n                        \"No number does all of that: two of the conditions contradict each other where their moduli overlap.\" ^0\n                    else:\n                        (\"x = \" + str(r[0]) + \" (mod \" + str(r[1]) + \"): \" + str(r[0]) + \", \" + str(r[0] + r[1]) + \", \" + str(r[0] + 2 * r[1]) + \", ...\") ^0\n                    return\n                (\"Type \" + str(len(rs)) + \" moduli from 2 to 1000000.\") ^0\n        else:\n            \"Type 2 to 4 whole numbers.\" ^0\n\ndef prime():\n    ask(\"number\", 2, 1000000000000000000) => n\n    if n == -1:\n        \"Cancelled.\" ^0\n        return\n    if n == 2:\n        \"2 is prime.\" ^0\n        return\n    if n % 2 == 0:\n        (str(n) + \" is even, so it is not prime.\") ^0\n        return\n    modular.power(2, n - 1, n)[0] => f\n    if f == 1:\n        (\"Fermat, base 2: 2^(n-1) mod n = 1 - it passes.\") ^0\n    else:\n        (\"Fermat, base 2: 2^(n-1) mod n = \" + str(f) + \", not 1 - so it is composite.\") ^0\n    modular.strong(n, 2) => mr\n    \"\" => line\n    for x in mr[3]:\n        if line != \"\":\n            line + \", \" => line\n        line + str(x) => line\n    (\"Miller-Rabin, base 2: n - 1 = 2^\" + str(mr[1]) + \" x \" + str(mr[2]) + \"; 2^\" + str(mr[2]) + \" and its squarings mod n: \" + line) ^0\n    if mr[0]:\n        \"  That is what a prime gives (1 at the start, or n - 1 on the way): it passes.\" ^0\n    else:\n        \"  A prime would give 1 at the start or n - 1 on the way: so it is composite, and base 2 is the witness.\" ^0\n    modular.is_prime(n) => p\n    if p:\n        (str(n) + \" is prime: it passes Miller-Rabin for the 13 bases 2 to 41, which is exact below 3.3 x 10^24.\") ^0\n    else:\n        (str(n) + \" is composite.\") ^0\n        if f == 1:\n            \"Base 2 is a Fermat liar for it.\" ^0\n        if mr[0]:\n            0 => w\n            for b in [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]:\n                if w == 0 and n % b != 0 and not modular.strong(n, b)[0]:\n                    b => w\n            if w > 0:\n                (\"Base 2 is a strong liar too; base \" + str(w) + \" is the first of the 13 to catch it.\") ^0\n            else:\n                \"Base 2 is a strong liar too; a small factor gives it away.\" ^0\n\n\"== Clock arithmetic ==\" ^0\n\"Working modulo m: powers, inverses, the Chinese remainder theorem, and testing primes.\" ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        pow_mod()\n    elif choice == \"2\":\n        inverse()\n    elif choice == \"3\":\n        remainders()\n    elif choice == \"4\":\n        prime()\n    elif choice == \"5\":\n        False => running\n    else:\n        \"Pick a number from 1 to 5.\" ^0\n\"Bye.\" ^0\n",
      "python": "import modular\n\ndef trim(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef whole(s):\n    if len(s) == 0 or len(s) > 18:\n        return -1\n    n = 0\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef ask(prompt, low, high):\n    while True:\n        a = trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \"))\n        if a == \"\":\n            return -1\n        n = whole(a)\n        if n >= low and n <= high:\n            return n\n        print(\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\")\n\ndef numbers(s):\n    out = []\n    w = \"\"\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if w != \"\":\n                v = whole(w)\n                if v < 0:\n                    return []\n                out = out + [v]\n            w = \"\"\n        else:\n            w = w + c\n    return out\n\ndef lpad(s, n):\n    while len(s) < n:\n        s = \" \" + s\n    return s\n\ndef pow_mod():\n    a = ask(\"base\", 0, 1000000000000000000)\n    if a == -1:\n        print(\"Cancelled.\")\n        return\n    e = ask(\"exponent\", 0, 1000000000000000000)\n    if e == -1:\n        print(\"Cancelled.\")\n        return\n    m = ask(\"modulus\", 2, 1000000000000000000)\n    if m == -1:\n        print(\"Cancelled.\")\n        return\n    r = modular.power(a, e, m)\n    if len(r[1]) <= 20:\n        print(\"  bit  base (squared each step)        result so far\")\n        for st in r[1]:\n            print(\"  \" + lpad(str(st[0]), 3) + \"  \" + lpad(str(st[1]), 24) + \"  \" + lpad(str(st[2]), 19))\n    print(str(a) + \"^\" + str(e) + \" mod \" + str(m) + \" = \" + str(r[0]))\n    print(\"One squaring for each of the exponent's \" + str(len(r[1])) + \" bits, every value kept below the modulus, instead of multiplying \" + str(e) + \" times.\")\n\ndef inverse():\n    a = ask(\"number\", 1, 1000000000000000000)\n    if a == -1:\n        print(\"Cancelled.\")\n        return\n    m = ask(\"modulus\", 2, 1000000000000000000)\n    if m == -1:\n        print(\"Cancelled.\")\n        return\n    e = modular.extended(a % m, m)\n    if len(e[3]) <= 20:\n        for row in e[3]:\n            print(\"  \" + str(row[0]) + \" = \" + str(row[2]) + \" x \" + str(row[1]) + \" + \" + str(row[0] - row[2] * row[1]))\n    if e[0] != 1:\n        print(str(a) + \" has no inverse modulo \" + str(m) + \": they share the factor \" + str(e[0]) + \".\")\n        return\n    x = modular.inverse(a, m)\n    print(\"Working back up the divisions: \" + str(a) + \" x \" + str(x) + \" = 1 (mod \" + str(m) + \"), so the inverse is \" + str(x) + \".\")\n\ndef remainders():\n    while True:\n        s = trim(input(\"remainders (2 to 4, like 2 3 2)> \"))\n        if s == \"\":\n            print(\"Cancelled.\")\n            return\n        rs = numbers(s)\n        if len(rs) >= 2 and len(rs) <= 4:\n            while True:\n                t = trim(input(\"moduli, as many, each 2 to 1000000 (like 3 5 7)> \"))\n                if t == \"\":\n                    print(\"Cancelled.\")\n                    return\n                ms = numbers(t)\n                ok = True\n                for m in ms:\n                    if m < 2 or m > 1000000:\n                        ok = False\n                if ok and len(ms) == len(rs):\n                    line = \"\"\n                    for i in range(0, len(ms)):\n                        if line != \"\":\n                            line = line + \", \"\n                        line = line + \"x = \" + str(rs[i]) + \" (mod \" + str(ms[i]) + \")\"\n                    print(line)\n                    r = modular.crt(rs, ms)\n                    if len(r) == 0:\n                        print(\"No number does all of that: two of the conditions contradict each other where their moduli overlap.\")\n                    else:\n                        print(\"x = \" + str(r[0]) + \" (mod \" + str(r[1]) + \"): \" + str(r[0]) + \", \" + str(r[0] + r[1]) + \", \" + str(r[0] + 2 * r[1]) + \", ...\")\n                    return\n                print(\"Type \" + str(len(rs)) + \" moduli from 2 to 1000000.\")\n        else:\n            print(\"Type 2 to 4 whole numbers.\")\n\ndef prime():\n    n = ask(\"number\", 2, 1000000000000000000)\n    if n == -1:\n        print(\"Cancelled.\")\n        return\n    if n == 2:\n        print(\"2 is prime.\")\n        return\n    if n % 2 == 0:\n        print(str(n) + \" is even, so it is not prime.\")\n        return\n    f = modular.power(2, n - 1, n)[0]\n    if f == 1:\n        print(\"Fermat, base 2: 2^(n-1) mod n = 1 - it passes.\")\n    else:\n        print(\"Fermat, base 2: 2^(n-1) mod n = \" + str(f) + \", not 1 - so it is composite.\")\n    mr = modular.strong(n, 2)\n    line = \"\"\n    for x in mr[3]:\n        if line != \"\":\n            line = line + \", \"\n        line = line + str(x)\n    print(\"Miller-Rabin, base 2: n - 1 = 2^\" + str(mr[1]) + \" x \" + str(mr[2]) + \"; 2^\" + str(mr[2]) + \" and its squarings mod n: \" + line)\n    if mr[0]:\n        print(\"  That is what a prime gives (1 at the start, or n - 1 on the way): it passes.\")\n    else:\n        print(\"  A prime would give 1 at the start or n - 1 on the way: so it is composite, and base 2 is the witness.\")\n    p = modular.is_prime(n)\n    if p:\n        print(str(n) + \" is prime: it passes Miller-Rabin for the 13 bases 2 to 41, which is exact below 3.3 x 10^24.\")\n    else:\n        print(str(n) + \" is composite.\")\n        if f == 1:\n            print(\"Base 2 is a Fermat liar for it.\")\n        if mr[0]:\n            w = 0\n            for b in [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]:\n                if w == 0 and n % b != 0 and not modular.strong(n, b)[0]:\n                    w = b\n            if w > 0:\n                print(\"Base 2 is a strong liar too; base \" + str(w) + \" is the first of the 13 to catch it.\")\n            else:\n                print(\"Base 2 is a strong liar too; a small factor gives it away.\")\n\nprint(\"== Clock arithmetic ==\")\nprint(\"Working modulo m: powers, inverses, the Chinese remainder theorem, and testing primes.\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        pow_mod()\n    elif choice == \"2\":\n        inverse()\n    elif choice == \"3\":\n        remainders()\n    elif choice == \"4\":\n        prime()\n    elif choice == \"5\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 5.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "modular.eml",
      "eml": "# P083 clock arithmetic - working modulo m: powers by repeated squaring, the\n# inverse by the extended Euclidean algorithm, the Chinese remainder\n# theorem, and two primality tests. Numbers go far past 2^53, so halving is\n# exact long division and nothing goes through a float; a % b is exact at\n# any size.\n\ndef half(n):\n    # n // 2 for n >= 0, digit by digit.\n    0 => q\n    0 => r\n    for ch in str(n):\n        r * 10 + int(ch) => r\n        0 => k\n        while r >= 2:\n            r - 2 => r\n            k + 1 => k\n        q * 10 + k => q\n    return q\n\ndef quotient(a, b):\n    # a // b for a >= 0, b > 0, digit by digit (at most 9 subtractions each).\n    0 => q\n    0 => r\n    for ch in str(a):\n        r * 10 + int(ch) => r\n        0 => k\n        while r >= b:\n            r - b => r\n            k + 1 => k\n        q * 10 + k => q\n    return q\n\ndef power(a, e, m):\n    # The corpus case modular-exponentiation: a^e mod m, squaring the base\n    # and multiplying it in for each 1 bit of e, from the lowest. Returns\n    # [result, steps], each step [bit, base before squaring, result so far].\n    1 % m => out\n    a % m => b\n    e => left\n    [] => steps\n    while left > 0:\n        left % 2 => bit\n        if bit == 1:\n            out * b % m => out\n        steps + [[bit, b, out]] => steps\n        half(left) => left\n        b * b % m => b\n    return [out, steps]\n\ndef extended(a, b):\n    # [g, x, y] with a x + b y = g = gcd(a, b), and the rows of the\n    # algorithm: [a, b, q] for each division.\n    [] => rows\n    1 => x0\n    0 => y0\n    0 => x1\n    1 => y1\n    while b != 0:\n        quotient(a, b) => q\n        rows + [[a, b, q]] => rows\n        a - q * b => r\n        b => a\n        r => b\n        x0 - q * x1 => t\n        x1 => x0\n        t => x1\n        y0 - q * y1 => t\n        y1 => y0\n        t => y1\n    return [a, x0, y0, rows]\n\ndef inverse(a, m):\n    # The x in 0..m-1 with a x = 1 (mod m), or -1 when gcd(a, m) is not 1.\n    extended(a % m, m) => e\n    if e[0] != 1:\n        return -1\n    return e[1] % m\n\ndef crt(rs, ms):\n    # x = r_i (mod m_i) for all i, combined two at a time. The moduli need\n    # not be coprime; when two conditions contradict there is no answer.\n    # Returns [x, modulus] or [] if none.\n    rs[0] % ms[0] => x\n    ms[0] => m\n    for i in [1:len(ms) - 1]:\n        ms[i] => n\n        rs[i] % n => r\n        extended(m, n) => e\n        e[0] => g\n        if (r - x) % g != 0:\n            return []\n        quotient(n, g) => step\n        # x + m t = r (mod n): t = ((r - x)/g) * (m/g)^-1 (mod n/g)\n        (r - x) % n => diff\n        quotient(diff, g) => k\n        inverse(quotient(m, g) % step, step) => inv\n        if step == 1:\n            0 => t\n        else:\n            k * inv % step => t\n        x + m * t => x\n        m * step => m\n        x % m => x\n    return [x, m]\n\ndef fermat(n, a):\n    # True when a^(n-1) = 1 (mod n): every prime passes for every a it does\n    # not divide; a composite that passes is a Fermat liar for base a.\n    return power(a, n - 1, n)[0] == 1\n\ndef strong(n, a):\n    # The Miller-Rabin test for base a, n odd > 2: n - 1 = 2^s d with d odd;\n    # a prime gives a^d = 1, or -1 at some squaring. Returns [passes, s, d,\n    # the sequence a^d, a^(2d), ... mod n].\n    n - 1 => d\n    0 => s\n    while d % 2 == 0:\n        half(d) => d\n        s + 1 => s\n    power(a, d, n)[0] => x\n    [x] => seq\n    (x == 1 or x == n - 1) => ok\n    for k in [1:s - 1]:\n        x * x % n => x\n        seq + [x] => seq\n        if x == n - 1:\n            True => ok\n    return [ok, s, d, seq]\n\ndef is_prime(n):\n    # Miller-Rabin with the first 13 primes as bases, which is known to be\n    # exact for every n below 3,317,044,064,679,887,385,961,981 (Sorenson\n    # and Webster, 2015) - far past the 10^18 the program accepts.\n    if n < 2:\n        return False\n    for p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]:\n        if n == p:\n            return True\n        if n % p == 0:\n            return False\n    for p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]:\n        if not strong(n, p)[0]:\n            return False\n    return True\n",
      "python": "def half(n):\n    q = 0\n    r = 0\n    for ch in str(n):\n        r = r * 10 + int(ch)\n        k = 0\n        while r >= 2:\n            r = r - 2\n            k = k + 1\n        q = q * 10 + k\n    return q\n\ndef quotient(a, b):\n    q = 0\n    r = 0\n    for ch in str(a):\n        r = r * 10 + int(ch)\n        k = 0\n        while r >= b:\n            r = r - b\n            k = k + 1\n        q = q * 10 + k\n    return q\n\ndef power(a, e, m):\n    out = 1 % m\n    b = a % m\n    left = e\n    steps = []\n    while left > 0:\n        bit = left % 2\n        if bit == 1:\n            out = out * b % m\n        steps = steps + [[bit, b, out]]\n        left = half(left)\n        b = b * b % m\n    return [out, steps]\n\ndef extended(a, b):\n    rows = []\n    x0 = 1\n    y0 = 0\n    x1 = 0\n    y1 = 1\n    while b != 0:\n        q = quotient(a, b)\n        rows = rows + [[a, b, q]]\n        r = a - q * b\n        a = b\n        b = r\n        t = x0 - q * x1\n        x0 = x1\n        x1 = t\n        t = y0 - q * y1\n        y0 = y1\n        y1 = t\n    return [a, x0, y0, rows]\n\ndef inverse(a, m):\n    e = extended(a % m, m)\n    if e[0] != 1:\n        return -1\n    return e[1] % m\n\ndef crt(rs, ms):\n    x = rs[0] % ms[0]\n    m = ms[0]\n    for i in range(1, len(ms)):\n        n = ms[i]\n        r = rs[i] % n\n        e = extended(m, n)\n        g = e[0]\n        if (r - x) % g != 0:\n            return []\n        step = quotient(n, g)\n        diff = (r - x) % n\n        k = quotient(diff, g)\n        inv = inverse(quotient(m, g) % step, step)\n        if step == 1:\n            t = 0\n        else:\n            t = k * inv % step\n        x = x + m * t\n        m = m * step\n        x = x % m\n    return [x, m]\n\ndef fermat(n, a):\n    return power(a, n - 1, n)[0] == 1\n\ndef strong(n, a):\n    d = n - 1\n    s = 0\n    while d % 2 == 0:\n        d = half(d)\n        s = s + 1\n    x = power(a, d, n)[0]\n    seq = [x]\n    ok = x == 1 or x == n - 1\n    for k in range(1, s):\n        x = x * x % n\n        seq = seq + [x]\n        if x == n - 1:\n            ok = True\n    return [ok, s, d, seq]\n\ndef is_prime(n):\n    if n < 2:\n        return False\n    for p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]:\n        if n == p:\n            return True\n        if n % p == 0:\n            return False\n    for p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]:\n        if not strong(n, p)[0]:\n            return False\n    return True\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n1\nabc\n1000000000000000001\n5\n-1\n3\n1\n\n2\n6\n9\n3\n1\n1 2 3 4 5\n1 2\n3\n1 1000001\n4 6\n4\n1\n4\n5\n",
      "screen": "== Clock arithmetic ==\nWorking modulo m: powers, inverses, the Chinese remainder theorem, and testing primes.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 0\nPick a number from 1 to 5.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> x\nPick a number from 1 to 5.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 1\nbase (0 to 1000000000000000000)> abc\nType a whole number from 0 to 1000000000000000000.\nbase (0 to 1000000000000000000)> 1000000000000000001\nType a whole number from 0 to 1000000000000000000.\nbase (0 to 1000000000000000000)> 5\nexponent (0 to 1000000000000000000)> -1\nType a whole number from 0 to 1000000000000000000.\nexponent (0 to 1000000000000000000)> 3\nmodulus (2 to 1000000000000000000)> 1\nType a whole number from 2 to 1000000000000000000.\nmodulus (2 to 1000000000000000000)> \nCancelled.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 2\nnumber (1 to 1000000000000000000)> 6\nmodulus (2 to 1000000000000000000)> 9\n  6 = 0 x 9 + 6\n  9 = 1 x 6 + 3\n  6 = 2 x 3 + 0\n6 has no inverse modulo 9: they share the factor 3.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 3\nremainders (2 to 4, like 2 3 2)> 1\nType 2 to 4 whole numbers.\nremainders (2 to 4, like 2 3 2)> 1 2 3 4 5\nType 2 to 4 whole numbers.\nremainders (2 to 4, like 2 3 2)> 1 2\nmoduli, as many, each 2 to 1000000 (like 3 5 7)> 3\nType 2 moduli from 2 to 1000000.\nmoduli, as many, each 2 to 1000000 (like 3 5 7)> 1 1000001\nType 2 moduli from 2 to 1000000.\nmoduli, as many, each 2 to 1000000 (like 3 5 7)> 4 6\nx = 1 (mod 4), x = 2 (mod 6)\nNo number does all of that: two of the conditions contradict each other where their moduli overlap.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 4\nnumber (2 to 1000000000000000000)> 1\nType a whole number from 2 to 1000000000000000000.\nnumber (2 to 1000000000000000000)> 4\n4 is even, so it is not prime.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n7\n1000\n13\n1\n2\n1000000000000\n1000000007\n2\n17\n3120\n2\n3\n1000000007\n3\n2 3 2\n3 5 7\n3\n1 2 3 4\n2 3 5 7\n4\n561\n4\n1000000007\n4\n3215031751\n4\n999999999999999989\n5\n",
      "screen": "== Clock arithmetic ==\nWorking modulo m: powers, inverses, the Chinese remainder theorem, and testing primes.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 1\nbase (0 to 1000000000000000000)> 7\nexponent (0 to 1000000000000000000)> 1000\nmodulus (2 to 1000000000000000000)> 13\n  bit  base (squared each step)        result so far\n    0                         7                    1\n    0                        10                    1\n    0                         9                    1\n    1                         3                    3\n    0                         9                    3\n    1                         3                    9\n    1                         9                    3\n    1                         3                    9\n    1                         9                    3\n    1                         3                    9\n7^1000 mod 13 = 9\nOne squaring for each of the exponent's 10 bits, every value kept below the modulus, instead of multiplying 1000 times.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 1\nbase (0 to 1000000000000000000)> 2\nexponent (0 to 1000000000000000000)> 1000000000000\nmodulus (2 to 1000000000000000000)> 1000000007\n2^1000000000000 mod 1000000007 = 959366170\nOne squaring for each of the exponent's 40 bits, every value kept below the modulus, instead of multiplying 1000000000000 times.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 2\nnumber (1 to 1000000000000000000)> 17\nmodulus (2 to 1000000000000000000)> 3120\n  17 = 0 x 3120 + 17\n  3120 = 183 x 17 + 9\n  17 = 1 x 9 + 8\n  9 = 1 x 8 + 1\n  8 = 8 x 1 + 0\nWorking back up the divisions: 17 x 2753 = 1 (mod 3120), so the inverse is 2753.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 2\nnumber (1 to 1000000000000000000)> 3\nmodulus (2 to 1000000000000000000)> 1000000007\n  3 = 0 x 1000000007 + 3\n  1000000007 = 333333335 x 3 + 2\n  3 = 1 x 2 + 1\n  2 = 2 x 1 + 0\nWorking back up the divisions: 3 x 333333336 = 1 (mod 1000000007), so the inverse is 333333336.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 3\nremainders (2 to 4, like 2 3 2)> 2 3 2\nmoduli, as many, each 2 to 1000000 (like 3 5 7)> 3 5 7\nx = 2 (mod 3), x = 3 (mod 5), x = 2 (mod 7)\nx = 23 (mod 105): 23, 128, 233, ...\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 3\nremainders (2 to 4, like 2 3 2)> 1 2 3 4\nmoduli, as many, each 2 to 1000000 (like 3 5 7)> 2 3 5 7\nx = 1 (mod 2), x = 2 (mod 3), x = 3 (mod 5), x = 4 (mod 7)\nx = 53 (mod 210): 53, 263, 473, ...\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 4\nnumber (2 to 1000000000000000000)> 561\nFermat, base 2: 2^(n-1) mod n = 1 - it passes.\nMiller-Rabin, base 2: n - 1 = 2^4 x 35; 2^35 and its squarings mod n: 263, 166, 67, 1\n  A prime would give 1 at the start or n - 1 on the way: so it is composite, and base 2 is the witness.\n561 is composite.\nBase 2 is a Fermat liar for it.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 4\nnumber (2 to 1000000000000000000)> 1000000007\nFermat, base 2: 2^(n-1) mod n = 1 - it passes.\nMiller-Rabin, base 2: n - 1 = 2^1 x 500000003; 2^500000003 and its squarings mod n: 1\n  That is what a prime gives (1 at the start, or n - 1 on the way): it passes.\n1000000007 is prime: it passes Miller-Rabin for the 13 bases 2 to 41, which is exact below 3.3 x 10^24.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 4\nnumber (2 to 1000000000000000000)> 3215031751\nFermat, base 2: 2^(n-1) mod n = 1 - it passes.\nMiller-Rabin, base 2: n - 1 = 2^1 x 1607515875; 2^1607515875 and its squarings mod n: 1\n  That is what a prime gives (1 at the start, or n - 1 on the way): it passes.\n3215031751 is composite.\nBase 2 is a Fermat liar for it.\nBase 2 is a strong liar too; base 11 is the first of the 13 to catch it.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 4\nnumber (2 to 1000000000000000000)> 999999999999999989\nFermat, base 2: 2^(n-1) mod n = 1 - it passes.\nMiller-Rabin, base 2: n - 1 = 2^2 x 249999999999999997; 2^249999999999999997 and its squarings mod n: 639232157799794134, 999999999999999988\n  That is what a prime gives (1 at the start, or n - 1 on the way): it passes.\n999999999999999989 is prime: it passes Miller-Rabin for the 13 bases 2 to 41, which is exact below 3.3 x 10^24.\n\n1) power mod m  2) inverse mod m  3) Chinese remainders  4) is it prime?  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "modular-exponentiation",
      "caseId": "117-modular-exponentiation",
      "title": "Modular exponentiation"
    }
  ],
  "updated": "2026-10-15"
}
