{
  "id": "P023",
  "slug": "number-toolkit",
  "key": "P023-number-toolkit",
  "title": "Number toolkit",
  "summary": "Whole-number tools from a text menu: is a number prime (and if not, its smallest factor), its prime factors with powers, the gcd and lcm of several numbers with Euclid's steps for two, the primes in a range by a sieve, a number's divisors - perfect, abundant or deficient - and the perfect numbers up to a limit.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P023 - Number toolkit\n\nWhole-number tools from a text menu: whether a number is prime (and if not,\nits smallest factor), its prime factors with powers, the gcd and lcm of two to\nten numbers - with Euclid's steps for two - the primes in a range, a number's\ndivisors and whether it is perfect, abundant or deficient, and the perfect\nnumbers up to a limit. Numbers go up to 10^12.\n\n- `main.eml` - the menu and its questions, with their checks, and what the\n  screen shows\n- `primes.eml` - smallest factor, prime factors, Euclid's algorithm, gcd and\n  the sieve\n- `divisors.eml` - divisors, the perfect/abundant/deficient test, and\n  perfect numbers up to a limit\n- `text.eml` - trimming, whole numbers, words and joining\n\nHow each part works:\n\n- Prime test and factors: trial division by 2 and then by odd numbers, only\n  while the divisor's square does not pass the number - at most a million\n  steps for 10^12, with every product exact. 600851475143 = 71 x 839 x 1471\n  x 6857.\n- gcd and lcm: Euclid's algorithm, folded over all the numbers; the lcm of\n  two is a / gcd x b. For two numbers each step a = q x b + r is shown.\n- Primes in a range: the sieve of Eratosthenes up to the end of the range\n  (at most 100,000), striking out the multiples of each prime from its\n  square; a range covers at most 1000 numbers.\n- Divisors: each d whose square does not pass n gives both d and n / d. A\n  number is perfect when its proper divisors add up to it (28 = 1 + 2 + 4 + 7\n  + 14), abundant when to more, deficient when to less.\n- Perfect numbers up to a limit (at most 10,000): every d is added to the\n  divisor sums of its multiples 2d, 3d, and so on - no division at all.\n\nThe lists the sieve and the divisor sums use are made in one step (`[True] *\n(n + 1)`) rather than grown an item at a time, which would copy the list on\nevery step.\n\nWhat is checked: a number is whole and in range for its question (0 to 10^12\nfor the prime test, 2 to 10^12 for factors, 1 to 10^12 otherwise); the gcd\ntakes two to ten numbers from 1 to 10^12; a range ends at or after its start\nand covers at most 1000 numbers up to 100,000; the perfect-number limit is 1\nto 10,000. Anything else asks again; nothing cancels.\n\nSessions: `sessions/basic.in` tests 1000003 (prime) and 1000001 (101 x\n9901), factors 360, 600851475143 and 97, finds the gcd and lcm of 84 and 36\nwith Euclid's steps and of 12, 18 and 30, lists the 25 primes up to 100, shows\nthe divisors of 28 (perfect) and 12 (abundant), and the perfect numbers up to\n10,000; `sessions/bad-input.in` types numbers that are words, negative or too\nlarge, 0 and 1, gcd input with one number, a word, a zero or eleven numbers,\nranges that run backwards, are too wide, hold one prime or none, the divisors\nof 1, and a limit with no perfect number below it.\n\nBuilt on the verified corpus cases `prime-checker` (trial division up to the\nsquare root), `prime-factorization` (dividing out each factor in turn),\n`gcd-lcm-calculator` (Euclid's algorithm, and the lcm from the gcd) and\n`perfect-number-checker` (adding up the proper divisors).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P023 number toolkit: primes, prime factors, gcd and lcm, primes in a range,\n# divisors, and perfect numbers - whole numbers up to 10^12.\nimport primes\nimport divisors\nimport text\n\n1000000000000 => biggest\n100000 => sieve_top\n1000 => widest_range\n10000 => perfect_top\n\ndef ask_number(prompt, low, high, message):\n    # A whole number from low to high, asked again until one is typed; -1 if\n    # the answer is empty, which cancels.\n    while True:\n        text.trim(input(prompt)) => answer\n        if answer == \"\":\n            return 0 - 1\n        text.number(answer) => n\n        if n >= low and n <= high:\n            return n\n        message ^0\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\ndef factor_text(fs):\n    # [[2, 3], [3, 2], [5, 1]] as \"2^3 x 3^2 x 5\".\n    [] => parts\n    for f in fs:\n        if f[1] == 1:\n            parts + [str(f[0])] => parts\n        else:\n            parts + [str(f[0]) + \"^\" + str(f[1])] => parts\n    return text.joined(parts, \" x \")\n\ndef in_lines(items, per_line):\n    # The items in rows of per_line, each row indented.\n    [] => lines\n    0 => i\n    while i < len(items):\n        lines + [\"  \" + text.joined(items[i:i + per_line], \", \")] => lines\n        i + per_line => i\n    return lines\n\n\"Whole numbers from 1 to 1,000,000,000,000 (10^12).\" => number_message\nTrue => running\nwhile running:\n    \"\" ^0\n    \"== Number toolkit ==\" ^0\n    \"1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\" ^0\n    \"5) divisors  6) perfect numbers  7) quit\" ^0\n    text.trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        ask_number(\"number> \", 0, biggest, \"Type a whole number from 0 to 10^12, or nothing to cancel.\") => n\n        if n == 0 - 1:\n            \"Cancelled.\" ^0\n        elif n < 2:\n            (str(n) + \" is neither prime nor composite.\") ^0\n        elif primes.smallest_factor(n) == n:\n            (str(n) + \" is prime.\") ^0\n        else:\n            (str(n) + \" is not prime; its smallest factor is \" + str(primes.smallest_factor(n)) + \".\") ^0\n    elif choice == \"2\":\n        ask_number(\"number> \", 2, biggest, \"Type a whole number from 2 to 10^12, or nothing to cancel.\") => n\n        if n == 0 - 1:\n            \"Cancelled.\" ^0\n        else:\n            primes.factors(n) => fs\n            if len(fs) == 1 and fs[0][1] == 1:\n                (str(n) + \" is prime.\") ^0\n            else:\n                (str(n) + \" = \" + factor_text(fs)) ^0\n    elif choice == \"3\":\n        None => nums\n        while nums == None:\n            text.trim(input(\"numbers (2 to 10, with spaces)> \")) => answer\n            if answer == \"\":\n                break\n            text.words(answer) => ws\n            [] => got\n            for w in ws:\n                text.number(w) => v\n                if v >= 1 and v <= biggest:\n                    got + [v] => got\n            if len(ws) >= 2 and len(ws) <= 10 and len(got) == len(ws):\n                got => nums\n            else:\n                \"Type two to ten whole numbers from 1 to 10^12, separated by spaces.\" ^0\n        if nums == None:\n            \"Cancelled.\" ^0\n        else:\n            nums[0] => g\n            nums[0] => l\n            for v in nums[1:len(nums)]:\n                primes.gcd(g, v) => g\n                primes.div(l, primes.gcd(l, v)) * v => l\n            if len(nums) == 2:\n                for s in primes.euclid(nums[0], nums[1]):\n                    (\"  \" + str(s[0]) + \" = \" + str(s[1]) + \" x \" + str(s[2]) + \" + \" + str(s[3])) ^0\n            (\"gcd = \" + str(g) + \", lcm = \" + str(l)) ^0\n    elif choice == \"4\":\n        ask_number(\"from> \", 1, sieve_top, \"Type a whole number from 1 to 100000, or nothing to cancel.\") => low\n        0 - 1 => high\n        while low != 0 - 1 and high == 0 - 1:\n            ask_number(\"to> \", 1, sieve_top, \"Type a whole number from 1 to 100000, or nothing to cancel.\") => high\n            if high == 0 - 1:\n                0 - 1 => low\n            elif high < low:\n                \"The range has to end at or after its start.\" ^0\n                0 - 1 => high\n            elif high - low >= widest_range:\n                (\"A range covers at most \" + str(widest_range) + \" numbers.\") ^0\n                0 - 1 => high\n        if low == 0 - 1:\n            \"Cancelled.\" ^0\n        else:\n            primes.sieve(low, high) => ps\n            if len(ps) == 0:\n                (\"No primes from \" + str(low) + \" to \" + str(high) + \".\") ^0\n            else:\n                (plural(len(ps), \"prime\") + \" from \" + str(low) + \" to \" + str(high) + \":\") ^0\n                for line in in_lines(ps, 10):\n                    line ^0\n    elif choice == \"5\":\n        ask_number(\"number> \", 1, biggest, \"Type a whole number from 1 to 10^12, or nothing to cancel.\") => n\n        if n == 0 - 1:\n            \"Cancelled.\" ^0\n        else:\n            divisors.divisors(n) => ds\n            divisors.kind(n) => k\n            (str(n) + \" has \" + plural(len(ds), \"divisor\") + \":\") ^0\n            for line in in_lines(ds, 10):\n                line ^0\n            (\"Its proper divisors add up to \" + str(k[0]) + \", so it is \" + k[1] + \".\") ^0\n    elif choice == \"6\":\n        ask_number(\"up to> \", 1, perfect_top, \"Type a whole number from 1 to 10000, or nothing to cancel.\") => top\n        if top == 0 - 1:\n            \"Cancelled.\" ^0\n        else:\n            divisors.perfect_up_to(top) => ps\n            if len(ps) == 0:\n                (\"No perfect numbers up to \" + str(top) + \".\") ^0\n            else:\n                (\"Perfect numbers up to \" + str(top) + \": \" + text.joined(ps, \", \")) ^0\n    elif choice == \"7\":\n        False => running\n    else:\n        \"Pick a number from 1 to 7.\" ^0\n\"Bye.\" ^0\n",
      "python": "import primes\nimport divisors\nimport text\nbiggest = 1000000000000\nsieve_top = 100000\nwidest_range = 1000\nperfect_top = 10000\n\ndef ask_number(prompt, low, high, message):\n    while True:\n        answer = text.trim(input(prompt))\n        if answer == \"\":\n            return 0 - 1\n        n = text.number(answer)\n        if n >= low and n <= high:\n            return n\n        print(message)\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\ndef factor_text(fs):\n    parts = []\n    for f in fs:\n        if f[1] == 1:\n            parts = parts + [str(f[0])]\n        else:\n            parts = parts + [str(f[0]) + \"^\" + str(f[1])]\n    return text.joined(parts, \" x \")\n\ndef in_lines(items, per_line):\n    lines = []\n    i = 0\n    while i < len(items):\n        lines = lines + [\"  \" + text.joined(items[i:i + per_line], \", \")]\n        i = i + per_line\n    return lines\n\nnumber_message = \"Whole numbers from 1 to 1,000,000,000,000 (10^12).\"\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"== Number toolkit ==\")\n    print(\"1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\")\n    print(\"5) divisors  6) perfect numbers  7) quit\")\n    choice = text.trim(input(\"choice> \"))\n    if choice == \"1\":\n        n = ask_number(\"number> \", 0, biggest, \"Type a whole number from 0 to 10^12, or nothing to cancel.\")\n        if n == 0 - 1:\n            print(\"Cancelled.\")\n        elif n < 2:\n            print(str(n) + \" is neither prime nor composite.\")\n        elif primes.smallest_factor(n) == n:\n            print(str(n) + \" is prime.\")\n        else:\n            print(str(n) + \" is not prime; its smallest factor is \" + str(primes.smallest_factor(n)) + \".\")\n    elif choice == \"2\":\n        n = ask_number(\"number> \", 2, biggest, \"Type a whole number from 2 to 10^12, or nothing to cancel.\")\n        if n == 0 - 1:\n            print(\"Cancelled.\")\n        else:\n            fs = primes.factors(n)\n            if len(fs) == 1 and fs[0][1] == 1:\n                print(str(n) + \" is prime.\")\n            else:\n                print(str(n) + \" = \" + factor_text(fs))\n    elif choice == \"3\":\n        nums = None\n        while nums == None:\n            answer = text.trim(input(\"numbers (2 to 10, with spaces)> \"))\n            if answer == \"\":\n                break\n            ws = text.words(answer)\n            got = []\n            for w in ws:\n                v = text.number(w)\n                if v >= 1 and v <= biggest:\n                    got = got + [v]\n            if len(ws) >= 2 and len(ws) <= 10 and len(got) == len(ws):\n                nums = got\n            else:\n                print(\"Type two to ten whole numbers from 1 to 10^12, separated by spaces.\")\n        if nums == None:\n            print(\"Cancelled.\")\n        else:\n            g = nums[0]\n            l = nums[0]\n            for v in nums[1:len(nums)]:\n                g = primes.gcd(g, v)\n                l = primes.div(l, primes.gcd(l, v)) * v\n            if len(nums) == 2:\n                for s in primes.euclid(nums[0], nums[1]):\n                    print(\"  \" + str(s[0]) + \" = \" + str(s[1]) + \" x \" + str(s[2]) + \" + \" + str(s[3]))\n            print(\"gcd = \" + str(g) + \", lcm = \" + str(l))\n    elif choice == \"4\":\n        low = ask_number(\"from> \", 1, sieve_top, \"Type a whole number from 1 to 100000, or nothing to cancel.\")\n        high = 0 - 1\n        while low != 0 - 1 and high == 0 - 1:\n            high = ask_number(\"to> \", 1, sieve_top, \"Type a whole number from 1 to 100000, or nothing to cancel.\")\n            if high == 0 - 1:\n                low = 0 - 1\n            elif high < low:\n                print(\"The range has to end at or after its start.\")\n                high = 0 - 1\n            elif high - low >= widest_range:\n                print(\"A range covers at most \" + str(widest_range) + \" numbers.\")\n                high = 0 - 1\n        if low == 0 - 1:\n            print(\"Cancelled.\")\n        else:\n            ps = primes.sieve(low, high)\n            if len(ps) == 0:\n                print(\"No primes from \" + str(low) + \" to \" + str(high) + \".\")\n            else:\n                print(plural(len(ps), \"prime\") + \" from \" + str(low) + \" to \" + str(high) + \":\")\n                for line in in_lines(ps, 10):\n                    print(line)\n    elif choice == \"5\":\n        n = ask_number(\"number> \", 1, biggest, \"Type a whole number from 1 to 10^12, or nothing to cancel.\")\n        if n == 0 - 1:\n            print(\"Cancelled.\")\n        else:\n            ds = divisors.divisors(n)\n            k = divisors.kind(n)\n            print(str(n) + \" has \" + plural(len(ds), \"divisor\") + \":\")\n            for line in in_lines(ds, 10):\n                print(line)\n            print(\"Its proper divisors add up to \" + str(k[0]) + \", so it is \" + k[1] + \".\")\n    elif choice == \"6\":\n        top = ask_number(\"up to> \", 1, perfect_top, \"Type a whole number from 1 to 10000, or nothing to cancel.\")\n        if top == 0 - 1:\n            print(\"Cancelled.\")\n        else:\n            ps = divisors.perfect_up_to(top)\n            if len(ps) == 0:\n                print(\"No perfect numbers up to \" + str(top) + \".\")\n            else:\n                print(\"Perfect numbers up to \" + str(top) + \": \" + text.joined(ps, \", \"))\n    elif choice == \"7\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 7.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "primes.eml",
      "eml": "# P023 number toolkit - primes, factors, gcd and lcm. Numbers go up to 10^12,\n# so trial division stops by 10^6 and every product stays exact.\n\ndef div(a, b):\n    # a // b for whole numbers a >= 0 and b > 0.\n    return int((a - a % b) / b)\n\ndef smallest_factor(n):\n    # The smallest factor of n >= 2 that is more than 1 (n itself if prime):\n    # 2, then the odd numbers whose square does not pass n.\n    if n % 2 == 0:\n        return 2\n    3 => d\n    while d * d <= n:\n        if n % d == 0:\n            return d\n        d + 2 => d\n    return n\n\ndef factors(n):\n    # The prime factors of n >= 2 as [prime, power] pairs, smallest first.\n    [] => out\n    2 => d\n    while d * d <= n:\n        if n % d == 0:\n            0 => power\n            while n % d == 0:\n                div(n, d) => n\n                power + 1 => power\n            out + [[d, power]] => out\n        if d == 2:\n            3 => d\n        else:\n            d + 2 => d\n    if n > 1:\n        out + [[n, 1]] => out\n    return out\n\ndef euclid(a, b):\n    # The steps of Euclid's algorithm for a and b, as [a, q, b, r] with\n    # a = q x b + r, down to the step whose remainder is 0.\n    [] => steps\n    while b > 0:\n        a % b => r\n        steps + [[a, div(a, b), b, r]] => steps\n        b => a\n        r => b\n    return steps\n\ndef gcd(a, b):\n    while b > 0:\n        a % b => r\n        b => a\n        r => b\n    return a\n\ndef sieve(low, high):\n    # The primes from low to high (high <= 100000), by the sieve of\n    # Eratosthenes: strike out every multiple of each prime from its square.\n    # One flag per number, made at once: growing a list one item at a time\n    # copies it every time.\n    [True] * (high + 1) => is_prime\n    False => is_prime[0]\n    if high >= 1:\n        False => is_prime[1]\n    2 => p\n    while p * p <= high:\n        if is_prime[p]:\n            p * p => m\n            while m <= high:\n                False => is_prime[m]\n                m + p => m\n        p + 1 => p\n    [] => out\n    for i in [low:high]:\n        if is_prime[i]:\n            out + [i] => out\n    return out\n",
      "python": "def div(a, b):\n    return int((a - a % b) / b)\n\ndef smallest_factor(n):\n    if n % 2 == 0:\n        return 2\n    d = 3\n    while d * d <= n:\n        if n % d == 0:\n            return d\n        d = d + 2\n    return n\n\ndef factors(n):\n    out = []\n    d = 2\n    while d * d <= n:\n        if n % d == 0:\n            power = 0\n            while n % d == 0:\n                n = div(n, d)\n                power = power + 1\n            out = out + [[d, power]]\n        if d == 2:\n            d = 3\n        else:\n            d = d + 2\n    if n > 1:\n        out = out + [[n, 1]]\n    return out\n\ndef euclid(a, b):\n    steps = []\n    while b > 0:\n        r = a % b\n        steps = steps + [[a, div(a, b), b, r]]\n        a = b\n        b = r\n    return steps\n\ndef gcd(a, b):\n    while b > 0:\n        r = a % b\n        a = b\n        b = r\n    return a\n\ndef sieve(low, high):\n    is_prime = [True] * (high + 1)\n    is_prime[0] = False\n    if high >= 1:\n        is_prime[1] = False\n    p = 2\n    while p * p <= high:\n        if is_prime[p]:\n            m = p * p\n            while m <= high:\n                is_prime[m] = False\n                m = m + p\n        p = p + 1\n    out = []\n    for i in range(low, high+1):\n        if is_prime[i]:\n            out = out + [i]\n    return out\n"
    },
    {
      "name": "divisors.eml",
      "eml": "# P023 number toolkit - divisors, and perfect, abundant and deficient numbers.\n# A number is perfect when its proper divisors (all but itself) add up to it,\n# abundant when they add up to more, deficient when to less.\nimport primes\n\ndef divisors(n):\n    # The divisors of n >= 1 in order: each d up to the square root gives d\n    # and n / d.\n    [] => small\n    [] => large\n    1 => d\n    while d * d <= n:\n        if n % d == 0:\n            small + [d] => small\n            if d * d != n:\n                [primes.div(n, d)] + large => large\n        d + 1 => d\n    return small + large\n\ndef kind(n):\n    # [sum of proper divisors, \"perfect\" | \"abundant\" | \"deficient\"].\n    0 => s\n    for d in divisors(n):\n        if d != n:\n            s + d => s\n    if s == n:\n        return [s, \"perfect\"]\n    if s > n:\n        return [s, \"abundant\"]\n    return [s, \"deficient\"]\n\ndef perfect_up_to(limit):\n    # The perfect numbers up to limit, by adding every d to the proper-divisor\n    # sums of its multiples 2d, 3d, ... (no division needed).\n    [0] * (limit + 1) => sums\n    1 => d\n    while d + d <= limit:\n        d + d => m\n        while m <= limit:\n            sums[m] + d => sums[m]\n            m + d => m\n        d + 1 => d\n    [] => out\n    for n in [2:limit]:\n        if sums[n] == n:\n            out + [n] => out\n    return out\n",
      "python": "import primes\n\ndef divisors(n):\n    small = []\n    large = []\n    d = 1\n    while d * d <= n:\n        if n % d == 0:\n            small = small + [d]\n            if d * d != n:\n                large = [primes.div(n, d)] + large\n        d = d + 1\n    return small + large\n\ndef kind(n):\n    s = 0\n    for d in divisors(n):\n        if d != n:\n            s = s + d\n    if s == n:\n        return [s, \"perfect\"]\n    if s > n:\n        return [s, \"abundant\"]\n    return [s, \"deficient\"]\n\ndef perfect_up_to(limit):\n    sums = [0] * (limit + 1)\n    d = 1\n    while d + d <= limit:\n        m = d + d\n        while m <= limit:\n            sums[m] = sums[m] + d\n            m = m + d\n        d = d + 1\n    out = []\n    for n in range(2, limit+1):\n        if sums[n] == n:\n            out = out + [n]\n    return out\n"
    },
    {
      "name": "text.eml",
      "eml": "# P023 number toolkit - reading what is typed. The interpreter that checks\n# every session does not run string methods yet, so the text handling is\n# written out here.\n\ndef trim(s):\n    # s without the spaces at either end.\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 number(s):\n    # The value of s if it is digits only (at least one, at most 13), otherwise\n    # -1.\n    if s == \"\" or len(s) > 13:\n        return 0 - 1\n    0 => n\n    for c in s:\n        if not (c in \"0123456789\"):\n            return 0 - 1\n        n * 10 + int(c) => n\n    return n\n\ndef words(s):\n    # The words of s, split at spaces and commas.\n    [] => out\n    \"\" => word\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                out + [word] => out\n            \"\" => word\n        else:\n            word + c => word\n    return out\n\ndef joined(items, sep):\n    \"\" => out\n    for i in [0:len(items) - 1]:\n        if i > 0:\n            out + sep => out\n        out + str(items[i]) => out\n    return out\n",
      "python": "def 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 number(s):\n    if s == \"\" or len(s) > 13:\n        return 0 - 1\n    n = 0\n    for c in s:\n        if not c in \"0123456789\":\n            return 0 - 1\n        n = n * 10 + int(c)\n    return n\n\ndef words(s):\n    out = []\n    word = \"\"\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                out = out + [word]\n            word = \"\"\n        else:\n            word = word + c\n    return out\n\ndef joined(items, sep):\n    out = \"\"\n    for i in range(0, len(items)):\n        if i > 0:\n            out = out + sep\n        out = out + str(items[i])\n    return out\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\n1\nabc\n-5\n1000000000001\n1\n1\n0\n2\n1\n\n3\n84\n84 x\n0 5\n1 2 3 4 5 6 7 8 9 10 11\n\n4\n50\n40\n1200\n54\n4\n24\n28\n5\n1\n6\n5\n7\n",
      "screen": "\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 0\nPick a number from 1 to 7.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 1\nnumber> abc\nType a whole number from 0 to 10^12, or nothing to cancel.\nnumber> -5\nType a whole number from 0 to 10^12, or nothing to cancel.\nnumber> 1000000000001\nType a whole number from 0 to 10^12, or nothing to cancel.\nnumber> 1\n1 is neither prime nor composite.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 1\nnumber> 0\n0 is neither prime nor composite.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 2\nnumber> 1\nType a whole number from 2 to 10^12, or nothing to cancel.\nnumber> \nCancelled.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 3\nnumbers (2 to 10, with spaces)> 84\nType two to ten whole numbers from 1 to 10^12, separated by spaces.\nnumbers (2 to 10, with spaces)> 84 x\nType two to ten whole numbers from 1 to 10^12, separated by spaces.\nnumbers (2 to 10, with spaces)> 0 5\nType two to ten whole numbers from 1 to 10^12, separated by spaces.\nnumbers (2 to 10, with spaces)> 1 2 3 4 5 6 7 8 9 10 11\nType two to ten whole numbers from 1 to 10^12, separated by spaces.\nnumbers (2 to 10, with spaces)> \nCancelled.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 4\nfrom> 50\nto> 40\nThe range has to end at or after its start.\nto> 1200\nA range covers at most 1000 numbers.\nto> 54\n1 prime from 50 to 54:\n  53\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 4\nfrom> 24\nto> 28\nNo primes from 24 to 28.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 5\nnumber> 1\n1 has 1 divisor:\n  1\nIts proper divisors add up to 0, so it is deficient.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 6\nup to> 5\nNo perfect numbers up to 5.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 7\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n1000003\n1\n1000001\n2\n360\n2\n600851475143\n2\n97\n3\n84 36\n3\n12, 18, 30\n4\n1\n100\n5\n28\n5\n12\n6\n10000\n7\n",
      "screen": "\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 1\nnumber> 1000003\n1000003 is prime.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 1\nnumber> 1000001\n1000001 is not prime; its smallest factor is 101.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 2\nnumber> 360\n360 = 2^3 x 3^2 x 5\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 2\nnumber> 600851475143\n600851475143 = 71 x 839 x 1471 x 6857\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 2\nnumber> 97\n97 is prime.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 3\nnumbers (2 to 10, with spaces)> 84 36\n  84 = 2 x 36 + 12\n  36 = 3 x 12 + 0\ngcd = 12, lcm = 252\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 3\nnumbers (2 to 10, with spaces)> 12, 18, 30\ngcd = 6, lcm = 180\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 4\nfrom> 1\nto> 100\n25 primes from 1 to 100:\n  2, 3, 5, 7, 11, 13, 17, 19, 23, 29\n  31, 37, 41, 43, 47, 53, 59, 61, 67, 71\n  73, 79, 83, 89, 97\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 5\nnumber> 28\n28 has 6 divisors:\n  1, 2, 4, 7, 14, 28\nIts proper divisors add up to 28, so it is perfect.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 5\nnumber> 12\n12 has 6 divisors:\n  1, 2, 3, 4, 6, 12\nIts proper divisors add up to 16, so it is abundant.\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 6\nup to> 10000\nPerfect numbers up to 10000: 6, 28, 496, 8128\n\n== Number toolkit ==\n1) is it prime  2) prime factors  3) gcd and lcm  4) primes in a range\n5) divisors  6) perfect numbers  7) quit\nchoice> 7\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "prime-checker",
      "caseId": "033-prime-checker",
      "title": "Prime checker"
    },
    {
      "slug": "prime-factorization",
      "caseId": "060-prime-factorization",
      "title": "Prime factorization"
    },
    {
      "slug": "gcd-lcm-calculator",
      "caseId": "023-gcd-lcm-calculator",
      "title": "GCD/LCM calculator"
    },
    {
      "slug": "perfect-number-checker",
      "caseId": "058-perfect-number-checker",
      "title": "Perfect number checker"
    }
  ],
  "updated": "2026-10-03"
}
