любители 12-ричной, там всё считается дюжинами (по 12), дюжинами дюжин (12 * 12 = 144) и т.д.
Есть историческая неточность, которая пробралась в рассуждения о компьютерах. Дескать, раз есть только 0 и 1, то это ограничивает компьютер в возможностях: есть только белое и чёрное, да и нет, а вот мы (люди) способны на полутона. Выбор основания системы счисления (количества цифр) произволен. Никакие математические действия, выкладки от этого не страдают, все такие системы эквивалентны. Компьютер может оперировать любыми числами, любыми полутонами. Из того, что у нас только 10 цифр, мы не ограничены в выборе только 10 вариантами. Всё-таки из цифр мы можем сконструировать любое число, например, 343 935 112
.
Выбор именно двоичной системы для компьютеров в первую очередь продиктован простотой создания (чем меньше состояний у системы, тем проще её моделировать). А кроме того, в двоичной системе счисления таблица умножения просто прекрасна:
1 * 1 = 1
.
Если бы мы выбрали двоичную систему счисления в качестве основной и у людей, нам бы не пришлось никогда учить таблицу умножения. А у тех, кто использует 12-ричную, таблица умножения наоборот, расширенная.
Мы часто в больших числах выделяем разряды по 3, чтобы было удобней читать, например:
2 726 382 293
.
Компьютер тоже выделяет разряды, но не по 3, а по 8. Например:
110 10110101 01101011 01011010 11101010
.
Можно ещё добавить 0 в начале, что бы все группы разрядов были полными:
0110 10110101 01101011 01011010 11101010
. Это если бы я сделал вот так в случае 10-ричного числа: 002 726 382 293
Один разряд в двоичном числе обычно называют битом, а группу из 8 — байтом.
В своих скриптах мы используем, естественно, привычные для нас числа, но внутри вычисления происходят все равно в двоичной системе. Вот пример вычислений на Python:
>>> (244 + 12) * 3
768
В компьютерах эти два вида чисел разделены: это данные разных типов.
У целых чисел нет дробной части (то, что после запятой), а у вещественных она может присутствовать. Это разделение кажется немного искусственным, однако оно основано на том, как целые и дробные числа хранятся в памяти.
В Python длина (точность) целых чисел ничем не ограничена (кроме размеров памяти, конечно).
Например, мы можем умножить 517 пятерок (5 * 5 * 5 ... * 5), то есть возвести 5 в 517 степень:
>>> 5 ** 517
23307314785000646072784266610821668241801473545626271544598494791269619953344119702925546532501336885504723760174487817041914775297579070814019265092475264660878939975996191804672512732082610196692020482390824733641919428939339084750099021321885071069679886560204219422928768932301614464518761290398229849521777054145309400479124661842433852143585681915283203125
У вещественных чисел ограничена точность: мы можем представить только какое-то определенное количество разрядов после запятой. Обычно это несколько десятков разрядов, что кажется избыточным для любых вычислений.
Например, если вы поделите 23 на 34, вы скорее всего запишите как ответ с точностью до 4-5 знаков после запятой, а не будете переписывать всё:
>>> 23 / 34
0.6764705882352942
В качестве десятичного разделителя в языках программирования используется .
, а не ,
.
Из-за фиксации количества разрядов все вычисления с вещественными числами примерные, а не точные:
>>> 0.3 - 0.1 - 0.1 - 0.1
-2.7755575615628914e-17
Мы должны были получить 0, а тут что-то странное.
Все хорошо. e-17
означает, что надо перенести запятую (точку) на 17 разрядов влево, то есть мы получили
-0.000000000000000027755575615628914
, что почти 0. Это иногда надо учитывать, именно из-за таких случаев бывают ошибки вида «Вы должны 0 рублей, 0 копеек, оплатите ваш долг до...» в СМС от банка. То есть число формально не точный 0, но округляя до сотых число, в котором первые 17 разрядов заполнены нулями, а всего разрядов 33, мы получаем 0.00.
С точки зрения работы с численными данными, компьютер можно считать продвинутым калькулятором. Только действия можно записывать не по одному, а все сразу:
>>> (12 + 6) * 134 / 3.4 + 20.6
730.0117647058823
Но можно и хранить промежуточные результаты:
>>> в_скобках = 12 + 6
>>> в_скобках * 134 / 3.4 + 20.6
730.0117647058823
Из всех типов данных только числа являются для компьютера естественными: всё, что он делает — операции с числами: сложение, умножение, перемещение из одного места в другое и т.д.
Возникает закономерный вопрос: «А как быть с более сложными данными?» Например, с текстами, изображениями, звуками.
Можно отчасти пошутить, отчасти сказать почти правду: никак.
Дело в том, что вопрос остальных данных — это вопрос интерпретации их для человека и скриптов, которые он пишет. Это вопрос кодирования и договорённостей. Иногда цветок на окне — это просто цветок, а иногда — некоторая информация или сигнал — например для шпиона, что на конспиративной квартире лучше не появляться.
Например, строка привет
хранится как последовательность 6 чисел (1087, 1088, 1080, 1074, 1077, 1090):
>>> s = "привет"
>>> for c in s:
print(ord(c))
1087
1088
1080
1074
1077
1090
То есть внутри — это какие-то двоичные числа. Но компьютер заботливо отображает их в виде символов.
Символы кириллицы кодируются как в алфавите, друг за другом:
>>> s = "абвгд"
>>> for c in s:
print(ord(c))
1072
1073
1074
1075
1076
Строчные буквы сразу после заглавных:
>>> ord('Я')
1071
>>> ord('а')
1072
Не будем сейчас поднимать вопрос о букве ё
, которая стоит не на своем месте:
>>> ord('д')
1076
>>> ord('е')
1077
>>> ord('ё')
1105
>>> ord('ж')
1078
Дело в том, что при кодировке кириллице буква ё
оказалась смещена в конец, как и все буквы с диакритическими знаками. Хотя буква й
находится на своем месте.
>>> ord('й')
1081
Кто определяет, какие символы какими числами кодируются? Сейчас практически всеми системами используется таблица Unicode, там есть все национальные алфавиты, иероглифы, эмодзи, пиктограммы и т.д. — несколько десятков тысяч символов. Например, там есть несколько снеговичков. Один из них — с кодом 9731.
>>> ord('☃')
9731
Если нам нужно отсортировать список фамилий, то сортировка может идти по числам, которыми закодированы символы, а мы будем воспринимать это как сортировку по алфавиту:
>>> s = ['Сидоров', 'Петров', 'Иванов']
>>> sorted(s)
['Иванов', 'Петров', 'Сидоров']
Мы можем превратить строку привет
в Привет
, отняв 32 от кода первого символа. Или воспользоваться специальной функцией Python под названием capitalize
, которая сделает это за нас:
>>> "заголовок новости".capitalize()
'Заголовок новости'
Но «под капотом» всё равно происходит замена одних чисел на другие.
Как видите — все данные (не только текст), в компьютере «оцифрованы» — превращены в последовательность чисел (байт) с определенной структурой.
Предположим, что мы хотим работать со структурированными данными. Например, в виде таблицы. У таблицы есть строки и столбцы:
За основу мы хотим принять обычный текст. Мы можем договориться, что каждая строка будет с новой строки, а столбцы будут отделяться друг от друга точкой с запятой:
Расходы;Месяц;Комментарий
1250;январь;
10500;февраль;Очень большое превышение. Почему?
Формально, это просто кусок данных, записанных в виде текста, но эти данные имеют структуру (разделение на строки и столбцы), поэтому некоторые символы отвечают за данные, а некоторые — за разметку (в данном случае — ;
).
Такой формат данных называется CSV (Comma-separated values: значения, разделенные запятыми). Его поддерживают большое количество программ, включая Excel. На рисунке сверху открыт именно этот CSV-файл. Разделитель в нем ;
— он такой по умолчанию в русскоязычной Windows, а в других регионах может быть другой.
Получается, у нас уже два слоя интерпретации.
В памяти компьютера находится последовательность чисел:
1056, 1072, 1089, 1093, 1086, 1076, 1099, 59, 1052, 1077, 1089, 1103, 1094, 59, 1050, 1086,
1084, 1084, 1077, 1085, 1090, 1072, 1088, 1080, 1081, 10, 49, 50, 53, 48, 59, 1103, 1085, 1074,
1072, 1088, 1100, 59, 10, 49, 48, 53, 48, 48, 59, 1092, 1077, 1074, 1088, 1072, 1083, 1100, 59,
1054, 1095, 1077, 1085, 1100, 32, 1073, 1086, 1083, 1100, 1096, 1086, 1077, 32, 1087, 1088, 1077,
1074, 1099, 1096, 1077, 1085, 1080, 1077, 46, 32, 1055, 1086, 1095, 1077, 1084, 1091, 63
Каждое число интерпретируется как код символа в таблице Unicode. Мы получаем текст:
Расходы;Месяц;Комментарий
1250;январь;
10500;февраль;Очень большое превышение. Почему?
Но это еще не конец, потому что в тексте есть структура, а не чистые данные. Нужно прочесть эту структуру, разделить всё на строки и столбцы и получить в итоге таблицу, как мы привыкли ее видеть:
Слоев интерпретации может быть еще больше. Возьмем обычный Word-документ, в котором есть фраза «Сегодня необычайно приятная погода!»:
Сохраним его под именем weather.docx
. Формат docx
— это на самом деле архив. Давайте переименуем его в weather.zip
, чтобы его открыл архиватор.
Как видим, там очень большое количество файлов и папок. Нас интересует только один из файлов — document.xml
.
В нем содержится вот такой текст:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid wp14"><w:body><w:p w:rsidR="00295D78" w:rsidRDefault="00730203"><w:r><w:t>Сегодня необычайно приятная погода!</w:t></w:r></w:p><w:p w:rsidR="00730203" w:rsidRPr="00730203" w:rsidRDefault="00730203"><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/></w:p><w:sectPr w:rsidR="00730203" w:rsidRPr="00730203"><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1134" w:right="850" w:bottom="1134" w:left="1701" w:header="708" w:footer="708" w:gutter="0"/><w:cols w:space="708"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w:document>
Все в одной строке, не видно структуры, давайте добавим отступов:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document
xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex"
xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex"
xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex"
xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex"
xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex"
xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex"
xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex"
xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex"
xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink"
xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid"
xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex"
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid wp14">
<w:body>
<w:p w:rsidR="00295D78" w:rsidRDefault="00730203">
<w:r>
<w:t>Сегодня необычайно приятная погода!</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00730203" w:rsidRPr="00730203" w:rsidRDefault="00730203">
<w:bookmarkStart w:id="0" w:name="_GoBack"/>
<w:bookmarkEnd w:id="0"/>
</w:p>
<w:sectPr w:rsidR="00730203" w:rsidRPr="00730203">
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1134" w:right="850" w:bottom="1134" w:left="1701" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
</w:document>
Это формат XML
, он тоже сделан на основе текста, там есть разметка данных и сами данные. Про него мы будем говорить позже. Сейчас отметим только, что там всё строится на основе открывающихся и закрывающихся тегов:
<ирония>Это как на указателях въезда и выезда из города</ирония>
.
Внутри этой разметки мы видим наш абзац:
<w:t>Сегодня необычайно приятная погода!</w:t>
Получается, что мы можем на основе одних форматов данных делать другие и получать слои интерпретации. Это как в сказке:
На море на океане есть остров, на том острове дуб стоит, под дубом сундук зарыт, в сундуке — заяц, в зайце — утка, в утке — яйцо, в яйце — игла, — смерть Кощея. А у нас. Есть документ, он — архив, в архиве — папка, в папке — документ, в документе — структура, внутри структуры — данные.
В следующей главе мы подробнее поговорим о том, что такое данные, разберемся с тем, как они могут быть распределены, какие описательные характеристики этих данных мы можем получить. Еще мы попробуем поработать с данными в Python и разберемся с тем, какие основные типы данных есть в этом языке.