{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
Peter Norvig, 2022
\n", "\n", "# The Babylonian Number System\n", "\n", "Our number system has ten digit symbols, 0 to 9, which we concatenate to form larger integers with the understanding that we are using base 10, which means that each digit is worth ten times as much as the one to the right of it. For example:\n", "\n", "$$409 = 4\\times10^2 + 0\\times10^1 + 9\\times10^0 = 400 + 0 + 9 = 409$$\n", "\n", "\n", "The ancient [**Babylonian cuneiform number system**](https://en.wikipedia.org/wiki/Babylonian_cuneiform_numerals) (circa 2000 BCE) had a number system that was different in three ways: \n", "1. They had no symbol for zero. \n", "2. It was base 60, not base 10. \n", "3. Instead of having 60 different symbols for the digits, they had just two symbols, for 1 and 10, and they used a tally system where you just put together as many 10s and 1s as you need (in any order) to make a \"digit\" from 1 to 59. \n", "\n", "Here are some examples:\n", "\n", "![](https://xjwfriends.files.wordpress.com/2018/02/babyloniannumbers.jpg)\n", "\n", "We will use the Unicode cuneiform characters `𒐕` to represent 1, and `𒌋` to represent 10. If you have trouble finding the right Unicode characters you can use `!` for 1 and `<` for 10.\n", "\n", "Thus, 59 can be represented as `𒌋𒌋𒌋𒌋𒌋𒐕𒐕𒐕𒐕𒐕𒐕𒐕𒐕𒐕` or `𒐕𒐕𒐕𒌋𒌋𒌋𒐕𒐕𒐕𒐕𒐕𒐕𒌋𒌋` or `<< int:\n", " \"Convert a base 60 Babylonian number string into an integer.\"\n", " return sum(d * 60 ** i for i, d in enumerate(reversed(digits(num))))\n", "\n", "def digits(num: str) -> List[int]:\n", " \"The list of integer digits for a Babylonian number\"\n", " return [sum(value[c] for c in group) for group in num.split(' ')]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An example:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "36191" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "babyl_to_int('𒌋 𒐕𒐕𒐕 𒌋𒐕')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 3, 11]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "digits('𒌋 𒐕𒐕𒐕 𒌋𒐕')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now a function to go in the other direction:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def int_to_babyl(n: int) -> str:\n", " \"\"\"Convert an integer into a base 60 Babylonian number string.\"\"\"\n", " return ' '.join((d // 10) * '𒌋' + (d % 10) * '𒐕' \n", " for d in to_base(n, 60))\n", " \n", "def to_base(n: int, base=60) -> List[int]:\n", " \"\"\"The list of integer digits for `n` in base `base`.\"\"\"\n", " return [n] if n < base else [*to_base(n // base, base), n % base]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'𒌋 𒐕𒐕𒐕 𒌋𒐕'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int_to_babyl(36191)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 3, 11]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "to_base(36191, 60)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is a more comprehensive test suite:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tests = [\n", " ( 0, [0], \"\", \" \"),\n", " ( 1, [1], \"𒐕\", \"!\"),\n", " ( 11, [11], \"𒌋𒐕\", \" bool:\n", " \"\"\"Each test is an integer `n`, the digits in base 60, and \n", " one or more ways of representing `n` as a Babylonian number strings.\"\"\"\n", " for (n, base60_digits, *nums) in tests:\n", " assert int_to_babyl(n) in nums, f'int_to_babyl({n})'\n", " assert digits(nums[0]) == to_base(n, 60) == base60_digits, f'digits({nums[0]!r})'\n", " for num in nums:\n", " assert babyl_to_int(num) == n, f'babyl_to_int({num!r})'\n", " return True\n", " \n", "test()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" } }, "nbformat": 4, "nbformat_minor": 4 }