Лайфхаки по программированию от Алана Тьюринга (Mark I/II)
В процессе обсуждения в комментариях соседней темы я набрёл на замечательное руководство от 1951 года по программированию серии одних из первых британских ЭВМ — Manchester/Ferranti Mark I/II за авторством самого Алана Тьюринга: curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/RobertTau/turing.pdf
И там на странице 55 есть замечательная секция «Programming Hints» — «Приёмы и трюки программирования».
Конечно я не мог не ознакомится с тем чем и как дышала передовая программерская мысль в 1951 году.
Для начала скопирую сюда немного ликбеза о том что это за ЭВМ вообще такая была (крайне сжато и только по верхушках, более обстоятельная обзорно-историческая статья возможно последует позднее).
Классическая архитектура аккумулятор-память. ОЗУ вместе с регистрами хранилось в электронно-лучевых трубках Уильсона.
20-битная инструкция как бы состоит из четырёх пятибитных алфавитно-цифровых символа. Как и в телеграфе весь алфавит и цифры в 32 значения не влазил, поэтому два символа были отведены под «изменение таблицы символов».
Но самое странное как выглядела таблица текстовых символов, а выглядела она вот так:
Здесь три колонки — номер по порядку, номер в бинарном коде и сам символ. Обратите внимание, что двоичные числа в команде Mark I было принято записывать с младшими разрядами справа!
Как видите никакой системы в расположении букв как будто бы нет. Но это вызвано тем, что эта битовая раскладка повторяет коды международного телеграфного кода тех лет:
Так вот программы составлялись этими вот буквенными кодами.
Вот как выглядит первый пример программы из книги Тьюринга:
Сразу не пугайтесь — тут всё просто. Первая колонка — это номер строки программы. / — это нулевой символ, E — это первый, @ — второй — посмотрите снова на таблицу. Т.е. в первой колонке просто выписаны по порядку числа от 0 до 10 в кодировке этой монументальной машины.
Сама программа находится во второй колонке — 20-битное число представлено четырьмя подряд идущими 5-битными буквами из которых первые две (10 бит) описывают номер ячейки памяти прошитый в инструкции, а последние две — код инструкции и так называемый код B-tube который позволяет делать индексации. Суровые манчестерские инженеры первые годы вот так вот и программировали — обложившись таблицами с перемешанными буквами, о чём см. ниже.
А вот теперь пойдём на страницу 55 руководства по второй ссылке в этом посте и посмотрим какие полезные приёмы и методики программирования пропагандировал в то время Алан Тьюринг:
Manoevring space / Место для манёвра
Редко когда кто сможет написать на страницу инструкции кода сразу в готовом виде — оставляйте между строками с инструкциями пустое место чтобы в случае чего вписать туда забытые команды. По опыту Тьюринга заполненными должны быть примерно 5/8 страницы, а 3/8 оставлены для возможности добавления. Пустые места следует оставлять между цельными последовательностями инструкций (т.е. выполняющих одно монолитное действие в несколько шагов).
(ассемблера с метками не было, поэтому сдвиг программы даже на одно слово был чреват)
Do programming directly in teleprint code / Программируйте прямо в кодах телетайпа
Пишите программу сразу символами телетайпа!
Counting procedure / Отсчитывающая процедура
Очень часто в программировании возникает задача повторения одной и той же последовательности инструкций заданное количество раз.
Тьюринг приводит общую схему решения такой задачи в двух вариантах — while и repeat.
Discrimination by control transfer / Выбор с передачей управления
Здесь Тьюринг рассматривает задачу case от целого числа. Используя индексные регистры машины он показывает как сделать goto по массиву переходов.
Omission of counting / Пропуск повторов
Иногда в случаях когда нужно совершить цикл малое число раз (например 3) и очень важна скорость, можно не делать инструкции цикла, а повторить инструкции подряд 3 раза.
(да да, разворачивание цикла)
Alternative entry / Альтернативная точка входа
Иногда нужно иметь почти одинаковые процедуры отличающиеся незначительными деталями. Зачастую такое можно организовать реализовав одно и то же тело процедуры с разными точками входа в неё, где и гнездится желаемая разница.
Changing sign in the accumulator / Смена знака аккумулятора
В Mark I прямолинейная смена знака аккумулятора возможна только в две инструкции, но Тьюринг обращает внимание на то, что инструкция вычитающая аккумулятор из единицы зачастую может быть отличным решением (видимо когда можно в дальнейшем просто поправить соседнее константное слагаемое).
Clearing the accumulator / Очистка аккумулятора
Новичок может впасть в заблуждение, что перед каждой серией вычислений аккумулятор нужно очищать. Тьюринг показывает что некоторые инструкции делают это автоматически.
Electronic space economy measures / Меры по сохранению места в электронной памяти
Электронная память (на ЭЛТ) в Mark I работает заметно быстрее более обширной памяти на магнитном барабане, поэтому предлагаются методы по её экономии, такие как размещение полезных данных в адресной части безадресной инструкции — например использованию безадресной инструкции как числа точности которого в части адресных бит достаточно чтобы содержимое кода инструкции (младшие разряды числа) не сказывались значимо на результате.
Следует признать, что многие трюки и приёмы программирования разработанные британскими инженерами во второй половине 40-х годов прошлого уже века всё еще актуальны для современного программирования (8-битных ретрокомпьютеров!).
И там на странице 55 есть замечательная секция «Programming Hints» — «Приёмы и трюки программирования».
Конечно я не мог не ознакомится с тем чем и как дышала передовая программерская мысль в 1951 году.
Для начала скопирую сюда немного ликбеза о том что это за ЭВМ вообще такая была (крайне сжато и только по верхушках, более обстоятельная обзорно-историческая статья возможно последует позднее).
Классическая архитектура аккумулятор-память. ОЗУ вместе с регистрами хранилось в электронно-лучевых трубках Уильсона.
20-битная инструкция как бы состоит из четырёх пятибитных алфавитно-цифровых символа. Как и в телеграфе весь алфавит и цифры в 32 значения не влазил, поэтому два символа были отведены под «изменение таблицы символов».
Но самое странное как выглядела таблица текстовых символов, а выглядела она вот так:
0 00000 / 8 00010 % 16 00001 T 24 00011 O
1 10000 E 9 10010 D 17 10001 Z 25 10011 B
2 01000 @ 10 01010 R 18 01001 L 26 01011 G
3 11000 A 11 11010 J 19 11001 W 27 11011 "
4 00100 : 12 00110 N 20 00101 H 28 00111 M
5 10100 S 13 10110 F 21 10101 Y 29 10111 X
6 01100 I 14 01110 C 22 01101 P 30 01111 V
7 11100 U 15 11110 K 23 11101 Q 31 11111 ?
Здесь три колонки — номер по порядку, номер в бинарном коде и сам символ. Обратите внимание, что двоичные числа в команде Mark I было принято записывать с младшими разрядами справа!
Как видите никакой системы в расположении букв как будто бы нет. Но это вызвано тем, что эта битовая раскладка повторяет коды международного телеграфного кода тех лет:
Так вот программы составлялись этими вот буквенными кодами.
Вот как выглядит первый пример программы из книги Тьюринга:
// /CT/
E/ DSTI
@/ D//H
A/ R//P
:/ /C/S
S/ :CT/
I/ @CTI
U/ :C/S
%/ JS/P
D/ A/
R/ @/
Сразу не пугайтесь — тут всё просто. Первая колонка — это номер строки программы. / — это нулевой символ, E — это первый, @ — второй — посмотрите снова на таблицу. Т.е. в первой колонке просто выписаны по порядку числа от 0 до 10 в кодировке этой монументальной машины.
Сама программа находится во второй колонке — 20-битное число представлено четырьмя подряд идущими 5-битными буквами из которых первые две (10 бит) описывают номер ячейки памяти прошитый в инструкции, а последние две — код инструкции и так называемый код B-tube который позволяет делать индексации. Суровые манчестерские инженеры первые годы вот так вот и программировали — обложившись таблицами с перемешанными буквами, о чём см. ниже.
А вот теперь пойдём на страницу 55 руководства по второй ссылке в этом посте и посмотрим какие полезные приёмы и методики программирования пропагандировал в то время Алан Тьюринг:
Manoevring space / Место для манёвра
Редко когда кто сможет написать на страницу инструкции кода сразу в готовом виде — оставляйте между строками с инструкциями пустое место чтобы в случае чего вписать туда забытые команды. По опыту Тьюринга заполненными должны быть примерно 5/8 страницы, а 3/8 оставлены для возможности добавления. Пустые места следует оставлять между цельными последовательностями инструкций (т.е. выполняющих одно монолитное действие в несколько шагов).
(ассемблера с метками не было, поэтому сдвиг программы даже на одно слово был чреват)
Do programming directly in teleprint code / Программируйте прямо в кодах телетайпа
Пишите программу сразу символами телетайпа!
It is never too soon to learn the meanings of the 64 functions [i.e., the opcodes].Храните листочек с расшифровками букв опкодов под рукой и пользуйтесь постоянно и всего через неделю вы будете заглядывать в этот листочек очень редко.
Counting procedure / Отсчитывающая процедура
Очень часто в программировании возникает задача повторения одной и той же последовательности инструкций заданное количество раз.
Тьюринг приводит общую схему решения такой задачи в двух вариантах — while и repeat.
Discrimination by control transfer / Выбор с передачей управления
Здесь Тьюринг рассматривает задачу case от целого числа. Используя индексные регистры машины он показывает как сделать goto по массиву переходов.
Omission of counting / Пропуск повторов
Иногда в случаях когда нужно совершить цикл малое число раз (например 3) и очень важна скорость, можно не делать инструкции цикла, а повторить инструкции подряд 3 раза.
(да да, разворачивание цикла)
Alternative entry / Альтернативная точка входа
Иногда нужно иметь почти одинаковые процедуры отличающиеся незначительными деталями. Зачастую такое можно организовать реализовав одно и то же тело процедуры с разными точками входа в неё, где и гнездится желаемая разница.
Changing sign in the accumulator / Смена знака аккумулятора
В Mark I прямолинейная смена знака аккумулятора возможна только в две инструкции, но Тьюринг обращает внимание на то, что инструкция вычитающая аккумулятор из единицы зачастую может быть отличным решением (видимо когда можно в дальнейшем просто поправить соседнее константное слагаемое).
Clearing the accumulator / Очистка аккумулятора
Новичок может впасть в заблуждение, что перед каждой серией вычислений аккумулятор нужно очищать. Тьюринг показывает что некоторые инструкции делают это автоматически.
Electronic space economy measures / Меры по сохранению места в электронной памяти
Электронная память (на ЭЛТ) в Mark I работает заметно быстрее более обширной памяти на магнитном барабане, поэтому предлагаются методы по её экономии, такие как размещение полезных данных в адресной части безадресной инструкции — например использованию безадресной инструкции как числа точности которого в части адресных бит достаточно чтобы содержимое кода инструкции (младшие разряды числа) не сказывались значимо на результате.
Следует признать, что многие трюки и приёмы программирования разработанные британскими инженерами во второй половине 40-х годов прошлого уже века всё еще актуальны для современного программирования (8-битных ретрокомпьютеров!).
6 комментариев
Раскопал, что такая странная кодировка на самом деле не странная, а просто повторяет кодировку британского телеграфного кода тех лет — вставил картинку в статью.
Но если учесть что Тьюринг — один из людей, сформировавший парадигму компьютерных вычислений вообще, я не уверен, что стоит сильно удивляться тому что мышление для современных компьютеров не особенно то и изменилось. Для смены парадигмы нужен ещё один Тьюринг.
Но забавным мне показался второй — Mark 1 Autocode, причём он довольно широко использовался, судя по википедии.
Пример программы:
Что можно интересного сказать:
— одна операция — одна строка
— 18 целочисленных переменных с именами от n1 до n18
— столько вещественных переменных сколько было доступно прочей памяти с именами вида v1..v999
— оператор j7 переходит на строку пронумерованную как 7, после запятой пишется условие
— если нужно обращаться с ячейками памяти как с массивом, то используется конструкция vnx, например vn10 которая означает переменную v… с номером который хранится в переменной n10
Конечно это было прямо несколько шагов вперёд по сравнению с программирование в символах телетайпа.
(Your text to link...)