Когда 42 — это цифра: шумеро-вавилонская система счисления с глиняных табличек

от автора

Шумеро-вавилонские клинописные глиняные таблички из Месопотамии содержат древнейшие известные математические тексты. Некоторым из них по пять тысяч лет и более.

Шумеро-вавилонская клинописная цифра 42 выглядит так: {𒐏𒐖}. И это именно цифра, которой может соответствовать и число 42_{10}, и 2520_{10}, и 151200_{10} и так далее, по степеням 60. В том числе, по обратным степеням, например: \frac{1}{42_{10}}, \frac{1}{2520_{10}}.

В шумеро-вавилонской Месопотамии использовали шестидесятеричную систему. То есть, позиционную систему по основанию шестьдесят: каждой позиции соответствует количество единиц, умноженное на степень 60, веса по позициям суммируются. Обычный способ. Поскольку основание 60_{10}, то нужно 59 цифр. Откуда и цифра 42 (конечно, 42 тут — это условное обозначение, поэтому к нему даже можно не приписывать нижний индекс _{10}). В клинописной записи отдельных цифр вертикальные «палки» обозначают единицы, если их количество не превышает 9, а «галки» — обозначают десятки, что, впрочем, не делает систему десятеричной.

Вообще, древнейшние шумерские системы счисления использовали для записи цифр круги и «полуовалы». «Галки» и «палки» появились позднее, когда система стала логически стройнее. К тому же, протоклинописных кругов и «полуовалов» всё ещё нет в Unicode. При этом, в самых древних шумерских вариантах интерпретация цифр зависела ещё и от того, что именно подсчитывается: использовался ли знак для обозначения мер зерновых, для записи количества кувшинов масла или площади земельного надела — числовое значение могло быть разным. Это в точности современный Javascript, неявно преобразующий строку в числовой тип.

Скрытый текст

Это эквивалентные операции, не сомневайтесь. Многие неотъемлемые части информацционных технологий очень древние. Предположим, что неявное преобразование типов приводит ASCII-код записи «42» в значение целочисленного типа 42. Это означает, что последовательность байтов 0x3432, превращается в 0x2A. Но парой байтов были обозначены ASCII-символы. У древнейших шумер были бы, предположим, кувшины с пивом, а не ASCII-символы. Не удивительно, что эффект был позднее исправлен (не в Javascript, который хорош и без пива).

Шумеро-вавилонская система счисления имеет целый ряд особенностей. Например, способ записи не подразумевал явного обозначения степени конкретной позиции: сколько там весит единица — 60, 60^{3} — всё определялось контекстом. Таким образом, это древнейшая система с плавающей точкой! И она на несколько тысяч лет старше всем привычных float, double, как и современных стандартов «плавающей точки» вообще. Впрочем, если в современных стандартах бывает два нуля, — вообще говоря, не равных друг другу, — то в шумеро-вавилонской системе настоящего нуля, как такового, вообще не было, хоть в поздних вариантах и появился знак для заполнения пустых разрядов.

Выбор числа 60_{10} в качестве основания имеет арифметическое обоснование. У шестидесятеричной системы большое преимущество, если сранивать, например, с десятеричной, а тем более — с двоичной, восьмеричной и шестнадцатеричной. Всё потому, что число шестьдесят — «очень непростое»: 60 = 2^{2} * 3 * 5. Арифметика записи по основанию шестьдесят оказывается удобной для учёта привычных долей — можно самые ходовые доли записать точно: \frac{1}{2}, \frac{1}{3}, \frac{1}{4}, \frac{1}{5}, \frac{1}{6}, \frac{1}{10}, \frac{1}{12}, \frac{1}{15}, \frac{1}{20}, \frac{1}{30}.

Итак, разберёмся с шумерскими цифрами. Цифрами служили комбинации клинописных знаков. Мы уже назвали их «галки» и «палки», соответственно внешнего вида в Unicode и на табличках. {𒌋} — это «галка», которая соответствует десяти единицам; {𒁹} — это «палка», которая соответствует единице. Единицы в количестве менее десяти записывались в виде плотного набора «палок»: {𒐛} — это семь. {𒑱𒐈} — это цифра, которой в единицах соответствует число 23_{10}. «Галки» повторялись кратно десяти.

В зависимости от позиции и от контекста цифра 23 может обозначать единицы, то есть нулевую степень основания 60_{10}, или единицы при 60^{1}, или единицы при 60^{2} = 3600. Соответственно, {𒑱𒐈} (23) в позиции единиц — это 23_{10}. {𒑱𒐈} в позиции 60^{1} это 23_{10} *  60_{10} = 1380_{10}. А для второй степени: 23_{10}  * {60_{10}}^{2} = 82800_{10}.

Позиции разделялись пробелами, что не всегда однозначно, так как нуля в классическом варианте не было. {𒐖}\quad{𒌋𒐈} это, например, 2*{60_{10}}^{1} + 13_{10} = 133_{10}. Почему «например»? Потому что это система с плавающей точкой. {𒐖}\quad{𒌋𒐈} с тем же успехом можно интерпретировать как 2_{10} + \frac{13}{60_{10}}.

Эта особенность сильно помогает при практических вычислениях, но мешает при считывании результата спустя всего лишь три-четыре тысячи лет. Всё достаточно просто. Различать клинья на реальных табличках трудно, но не схему записи.

Использование шумерской шестидесятеричной системы счисления в точности являлось прикладным случаем того, что сейчас принято называть «компьютерными науками» (computer science). Поэтому очень полезен сравнительный взгляд, учитывающий другие позиционные системы счисления, используемые в информатике и в тех самых компьютерных науках сейчас.

Старинная шутка гласит, что типов людей всего 10 — одни уже знают двоичную систему счисления, а другие — ещё нет. Система счисления — это способ записи чисел. Разные системы хорошо подходят для разных целей. Так, двоичная система подходит не только для записи шуток (10_{2} = 2_{10}), но и служит неплохим математическим фундаментом «железячных» компьютерных вычислений: компьютеры, как известно, не считают, а переключают транзисторные «флип-флопы». Успешная интерпретация таких переключений возможна только потому, что есть двоичная система счисления.

Использование систем счисления с разными основаниями является привычной практикой: кроме двоичной и десятичной, распространены восьмеричная и шестнадцатеричная. Восьмеричная система, конечно, встречается нынче реже, чем шестнадцатеричная, но всё равно постоянно присутствует рядом с вами, если вы сетевой инженер или разработчик системного ПО. Например, один из штатных способов записи IP-адреса, при вызове тех или иных утилит, использует восьмеричную систему, вот так: 010.010.010.010 — это будет 8.8.8.8 в привычной форме по основанию 10 (десять). Согласно древнему соглашению, октет IPv4-адреса, начинающийся с нуля, интерпретируется как записанный в восьмеричной системе. На табличках из Месопотамии об этом ничего не сказано, но, из-за базовых unix-библиотек, такое преобразование сейчас касается не только октетов.

А вот шестнадцатеричная система вряд ли нуждается в примерах: этот вариант встречается в практике программирования почти столь же часто, как и система десятичная. И не только в программировании. На стороне веб-фронтендеров в шестнадцатеричной системе повсеместно записываются цвета внутри каскадных таблиц стилей (CSS) — загляните хоть бы и в исходный код веб-страниц «Хабра». По основанию 16_{10} очень удобно записывать байтовые маски: запись получается не такой длинной, как в двоичной, а один октет укладывается в две цифры.

Более того, каждую шестнадцатеричную цифру полубайта можно выкинуть на четырёх пальцах руки, перпендикулярных большому пальцу: 0xF — всё четыре пальца. 0x8 — указательный или мизинец, в зависимости от того, «тупоконечные» у вас пальцы или «остроконечные». Не в смысле формы, а в смысле, с какой стороны старший бит байта. При работе с древними компьютерами (не глиняными, но примерно того же поколения) правильная шестнадцатеричная распальцовка сильно ускоряла набор на битовых переключателях. Нынче навык сей доступен разве что редкому динозавру-технарю, да и не так полезен, однако верная «распальцовка» всё ещё может быть эффективно использована в беседе с молодыми DevOps, для пущего их убеждения.

Не факт, что старшинство указательного пальца, взятое по модулю «хиральности» (правой/левой руки), оказало влияние на развитие систем счисления. Но вполне возможно, что принцип счёта по трём фалангам каждого из четырёх пальцев прямо связан с двенадцатеричными системами, которые мы здесь не рассматриваем. Впрочем, как раз 12_{10} * 5_{10} = 60_{10}.

Выше мы заметили, что основание 60 позволяет едва ли не каждую привычную на практике долю записать точно. Благодаря этой возможности шестидесятеричная система превосходит десятеричную и другие системы. Разберёмся, что именно тут имеется в виду.

Всякую позиционную систему счисления можно использовать для записи дробей: возьмём обратные степени основания {-1, -2, -3…} и станем записывать дробную часть, отделив её от целой каким-нибудь знаком. Точкой, например. Это уже было проделано выше. Для десяти — получаем всем привычные десятичные дроби: 0.4242. Точно так же будут работать и двоичная, и восьмеричная, и шестнадцатеричная система. Нет разницы. Только вот с записью долей таким способом возникнет сложность иного рода: запись окажется «бесконечной вправо» (ну, если записывать числа и расставлять веса справа налево; «бесконечная влево» запись — это p-адические числа, другая тема, хоть и неожиданно близкая).

Так, 16 — это 2^{4}. То есть, основание шестнадцатеричной системы, при всём богатстве выбора, какое-то слишком «простое», и проблемы начнутся с нечётными знаменателями в долях вида \frac{a}{b}.

Например, \frac{1}{5} = 0.33(3)_{16}всё в шестнадцатеричной системе, а тройка здесь — в периоде (обозначается скобками). «В периоде» — это значит, что развернутая запись никогда не окончится. Однако в десятичной записи \frac{1}{5} = 0.2_{10}. «Периода» нет, запись терминируется тут же. И это одно и то же рациональное число — одна пятая.

Да, формально, и 0.33(3)_{16}, благодаря возможности обозначить «периодические цифры», — это точная конечная запись для \frac{1}{5}. Да, к 0.2_{10}, если уж быть максимально строгим, должен быть приписан бесконечный хвост нулей — 0.2(0), но его принято не указывать (да вообще мало кто помнит, что он там есть, но его не видно; как и про второе представление с бесконечно повторяющимися девятками, для десятичной системы). Это всё так по определению, а требуется по тем же причинам, по которым в десятеричной (десятичной) системе 0.9(9)_{10} = 1.

Казалось бы, сложно ли записать (3) как период? Всего лишь скобки. Однако проблема в том, что длина периодической части может быть произвольной, не обязательно лишь одна цифра повторяется.

Заметьте, что 0.3_{16} * 5 = 0.F_{16}. Аналогично тому, как 0.3_{10} * 3_{10} = 0.9_{10}. Но почему в десятичной системе \frac{1}{5} = 0.2? Потому что 10_{10} = 2*5. Соответственно, все числа, представимые в виде 2^{n} * 5^{m}, будут регулярными в десятичной системе: «обратные» к ним можно записать в виде конечной дроби. Шестнадцатеричная же система имеет основание 2^{4}, а число 5 нельзя представить в виде 2^{n}, отсюда и десятичная часть в периоде.

По тем же причинам и 1/7_{16} = 0.249(249)_{16}. Три цифры период.

А вот для (\frac{1}{7^{11}})_{16} период записи после запятой составит 847425747 шестнадцатеричных цифр (проверьте на калькуляторе). Так что проблема точной записи, даже если позволяется вводить дополнительную структуру и указывать «период» в скобках, — остаётся. Кстати, поскольку в разложении 10 есть 2, то найти столь же иллюстративный обратный пример — число, которое «хорошо» представляется в десятичной системе, но «плохо» в шестнадцатеричной, — не выйдет.

Будем обозначать клинописные цифры десятичной записью соответствующего числа, разделять цифры будем запятой «,», а точку-разделитель целой и дробной части (мантиссы) — обозначим точкой с запятой («;»). Это общепринятый сейчас способ. Тогда \frac{1}{7} в шестидесятеричной шумеро-вавилонской системе это 0; 8,34,17(,8,34,17) или, если клинописью, {𒐜}\quad{𒌍𒐘}\quad{𒌋𒐛}\quad({𒐜}\quad{𒌍𒐘}\quad{𒌋𒐛})... (сила Unicode; которая хороша там, где реально требуется).

А что ещё за «обратные»? Например, в десятеричной системе деление на два эквивалентно умножению на пять с последующим сдвигом десятичной точки. Элементарный пример: 7/2 = (7 * 5)/10_{10} = 35_{10}/10_{10} = 3.5_{10}. В шестидесятеричной системе основание делится не только на 2 и 5, но ещё и на 3. В шестидесятеричной системе регулярные числа — это все те, которые представимы в виде 2^{n} * 3^{l} * 5^{m}. Здесь много делителей: [1, 2, 3, 4, 5, 6, 10_{10}, 12_{10}, 15_{10}, 20_{10}, 30_{10}, 60_{10}]. Поэтому больше долей записываются точно.

В древней шумеро-вавилонской практической арифметике деление одного числа на другое выполняется с помощью специальных таблиц. Чтобы найти \frac{A}{B}, древний инженер-информатик берёт «таблицу обратных» и находит число, обратное к B. Обратите внимание, что это не совсем те обратные, не совсем \frac{1}{B} — обратное здесь берётся по основанию системы счисления. Так, в десятеричном примере выше (\frac{7}{2}), обратное к \frac{1}{2} — это 5. Почему? Потому что 5 * 2 = 10_{10}, то есть \frac{2}{10} при умножении на 5 дают единицу.

Если принять плавающую точку, то 1 в нулевом разряде, если сдвинуть точку вправо, даст 10_{10} и т.д. Поэтому, в десятеричном примере, определив обратное 5, нужно посмотреть в таблицу умножения, найти там 5*7 = 35_{10}, выписать ответ и не забыть сдвинуть десятичную точку: 3.5_{10}. Так что именно плавающая точка позволяет нормировать имеющиеся числа, приводя их к удобной для вычислений форме записи. Умение работать с такими таблицами очень актуально, ведь в древней Месопотамии нет даже механических арифмометров (ну, скорее всего, их либо нет, либо они слишком дорого стоят). А вот глиняные таблички умножения и взятия обратных для шестидесятеричной системы есть.

Разделим 10,30 на 1,15. Это шумерские цифры. То есть, 10,30 = 630_{10}, а 1,15 = 75_{10}. Найдём обратный к 1,15 — это 48, потому что 1,15 * 48 = 1 (то есть, 3600_{10}). Найдём результат умножения 48 на 10,30. Это 8,24 (а нуля у нас нет — не забывайте). Поставим «плавующую точку» на место и вот результат: 8; 24.

То же самое в клинописных цифрах, как это делал бы инженер-информатик в Месопотамии несколько тысяч лет назад, превращая LaTeX в засечки на глине:

\frac{{𒌋}\quad{𒌍}}{{𒐕}\quad{𒌋}{𒐙}} (здесь черта — знак деления),

обратный: {𒐏𒐜}, умножаем по таблице:{𒐏𒐜} * {𒌋}\quad{𒌍}.

Результат: {𒐜}\qquad{𒑱𒐘} — и через те самые несколько тысяч лет придётся догадываться, где же здесь стоит плавающая точка.

Чуть выше мы нашли, что 1/7 в шумеро-вавилонской системе не представляется точно, потому что запись будет бесконечной: {𒐜}\quad{𒌍𒐘}\quad{𒌋𒐛}\quad({𒐜}\quad{𒌍𒐘}\quad{𒌋𒐛}).... Так происходит потому, что 7 — взаимно простое с основанием 60_{10}. Скорее всего, для древнего шумерского инженера-информатика рациональное число \frac{1}{7} не было бы «рациональным», в том смысле, что такую долю невозможно записать точно в шестидесятеричной системе, а в точных таблицах нет обратного значения. Непонятно, как считать, поэтому \frac{1}{7} не должна встречаться на практике. Конечно, если \frac{1}{7} всё же встретилась, то инженеру-информатику пришлось бы воспользоваться таблицами «приближённых» значений, подобрав подходящий интервал. Такие таблицы тоже имелись, но их наверняка старались избегать, ведь иначе шестидесятеричная система оказывается избыточной.

Литература

  • Knuth, D., 1972. Ancient Babylonian Algorithms. Commun. ACM 15 (7)

  • Daniel F. Mansfield, N.J. Wildberger. Plimpton 322 is Babylonian Exact Sexagesimal Trigonometry


ссылка на оригинал статьи https://habr.com/ru/articles/925154/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *