Arithmetica, или Python для инженеров и исследователей

Занько Ф.С.

Посвящается моему отцу -
Станиславу Филипповичу Занько

Содержание

  1. Введение
  2. Число

  3. Функция
  4. Дифференцирование и интегрирование функций

0. Введение

О названии, цели и задачах курса

На всей землѣ былъ одинъ языкъ и одно нарѣчiе. Двинувшись съ Востока, они нашли въ землѣ Сеннааръ равнину и поселились тамъ. И сказали другъ другу: надѣлаемъ кирпичей и обожжемъ огнемъ. И стали у нихъ кирпичи вмѣсто камней, а земляная смола вмѣсто извести. И сказали они: построимъ себѣ городъ и башню, высотою до небесъ, и сдѣлаемъ себѣ имя, прежде нежели разсѣемся по лицу всей земли. И сошелъ Господь посмотрѣть городъ и башню, которые строили сыны человѣческiе. И сказалъ Господь: вотъ, одинъ народъ, и одинъ у всѣхъ языкъ; и вотъ что начали они дѣлать, и не отстанутъ они отъ того, что задумали дѣлать; сойдемъ же и смѣшаемъ тамъ языкъ ихъ, такъ чтобы одинъ не понималъ рѣчи другаго. И разсѣялъ ихъ Господь оттуда по всей землѣ; и они перестали строить городъ.
(Быт.11:1-8)

Я глубоко убежден в единстве, целостности и красоте окружающего мира. Но сегодня наши представления и знания о нем напоминают скорее беспорядочно сваленную груду кирпичей, чем стройное здание.

Так было не всегда. Мировоззрение мудрецов древности, каким бы устаревшим оно нам ни казалось, безусловно было единым и целостным. Но люди универсально образованные, с синтетическим складом ума, такие как Леонардо да Винчи, Блез Паскаль, Александр Любищев, нашему времени чужды.

"Специализация наук начинается как раз в ту эпоху, которая назвала цивилизованного человека "энциклопедическим". XIX век начал свою историю под водительством людей, которые жили еще как энциклопедисты, хотя их творческая работа носила уже печать специализации. В следующем поколении центр тяжести перемещается: специализация в каждом ученом оттесняет общую культуру на задний план. Около 1890 г., когда третье поколение взяло на себя духовное водительство в Европе, мы видим уже новый тип ученого, беспримерный в истории. Это - человек, который из всего, что необходимо знать, знаком лишь с одной из наук, да и из той он знает лишь малую часть, в которой непосредственно работает. Он даже считает достоинством отсутствие интереса ко всему, что лежит за пределами его узкой специальности, и называет "дилетантством" всякий интерес к широкому знанию.

Этому типу ученого действительно удалось на своем узком секторе сделать открытия и продвинуть свою науку - которую он сам едва знает,- а попутно послужить и всей совокупности знаний, которую он сознательно игнорирует. Как же это стало возможным? Как это возможно сейчас? Мы стоим здесь перед парадоксальным, невероятным и в то же время неоспоримым фактом: экспериментальные науки развились главным образом благодаря работе людей посредственных, даже более чем посредственных. Иначе говоря, современная наука, корень и символ нашей цивилизации, впустила в свои недра человека заурядного и позволила ему работать с видимым успехом. Причина этого - в том факте, который является одновременно и огромным достижением, и грозной опасностью для новой науки и для всей цивилизации, направляемой и представляемой наукой; а именно - в механизации.

Большая часть работы в физике или биологии состоит в механических операциях, доступных каждому или почти каждому. Для производства бесчисленных исследований наука подразделена на мелкие участки, и исследователь может спокойно сосредоточиться на одном из них, оставив без внимания остальные. Серьезность и точность методов исследования позволяют применять это временное, но вполне реальное расчленение науки для практических целей. Работа, ведущаяся этими методами, идет механически, как машина, и, для того, чтобы получить результаты, научному работнику вовсе не нужно обладать широкими знаниями общего характера. Таким образом, большинство ученых способствуют общему прогрессу науки, не выходя из узких рамок своей лаборатории, замурованные в ней, как пчелы в сотах...

Прямой результат этой неумеренной специализации - тот парадоксальный факт, что, хотя сегодня "ученых" больше, чем когда-либо, подлинно образованных людей гораздо меньше, чем, например, в 1750 г. И хуже всего то, что вращающие "ворот науки", не в состоянии обеспечить подлинный ее прогресс. Для этого необходимо время от времени регулировать ее развитие, производить реконструкцию, перегруппировку, унификацию; но эта работа требует синтетических способностей, а синтез становится все труднее, так как поле действия расширяется, включая новые и новые области. Ньютон мог построить свою теорию физики без особых познаний в философии, Эйнштейн уже должен был хорошо знать Канта и Маха, чтобы прийти к своим выводам. Кант и Мах (я беру эти имена лишь как символы той огромной работы, какую проделал Эйнштейн) освободили ум Эйнштейна, расчистили ему дорогу к открытиям. Но одного Эйнштейна мало. Физика вступает в едва ли не тягчайший из кризисов своей истории; ее может спасти только новая "Энциклопедия", более систематическая, чем первая.

Итак, специализация, которая в течение столетия обеспечивала прогресс экспериментальных наук, приближается к состоянию, когда она не сможет больше продолжать это дело, если новое поколение не снабдит ее более подходящей организацией и новыми людьми" (Х.Ортега-и-Гассет. Восстание масс).

Эта книга начиналась как учебный курс по Python для инженеров и исследователей. Но человеческая мысль живет по своим законам, и первоначальный замысел претерпел существенные изменения.

Постепенно пришло понимание, что обучение языку Python или даже программированию вообще - не должно быть главной целью. Это только инструменты, конечно прекрасные и полезные. Для плотника важно уметь работать топором, но не в этом смысл плотницкого ремесла. Программирование - один из десятков вузовских предметов, Python - один из сотен существующих языков программирования. Поставить во главу угла Python и писать о нем книгу - значит сделать еще один шаг в направлении специализации, которая и так уже расщепила наше мировоззрение на атомы.

В наше время гораздо важнее создавать синтетические учебные курсы, направленные на воссоздание целостного миросозерцания. Но как это сделать, когда каждая дисциплина имеет свою терминологию, свой методологический аппарат и "один не понимает речи другого"? Синтез, объединение, взаимопонимание могут быть осуществлены только на базе общего языка, который неизбежно должен быть философским. Философия - это единственный универсальный язык, подходящий для создания целостного мировоззрения.

В результате, в тексте стали появляться философские рассуждения; неожиданно оказалось, что основной учебный материал нужно заимствовать из занимательной математики; никуда не делась и чисто техническая информация о Python. Очевидно, что назвать этот эклектичный набор сведений из весьма разных областей знаний обучающим курсом по Python, значит окончательно сбить с толку читателя.

Поэтому название книги пришлось переменить на "Arithmetica". В наши дни арифметика прочно ассоциируется со школьными вычислениями столбиком. Но в античности и в средневековье смысл этого слова был совсем другим - это наука о божественных числах, задающих космический порядок всего сущего. Около тысячи лет arithmetica была частью классического образования, состоявшего из семи свободных искусств: грамматики, логики, риторики, арифметики, геометрии, астрономии и музыки.

Если разобраться, программирование и математика - это фактически одно и то же, а исследование с помощью компьютера того, как число проявляет себя в окружающем мире, и есть arithmetica. В идеале это и должно быть основой подготовки инженера и исследователя.

Программирование - уникальный предмет, где обучающийся сталкивается с инженерным искусством как таковым. В так называемых "инженерных" дисциплинах обучение носит по большей части теоретический характер, расчеты просты и до проектирования конструкций, которые будут реально воплощены в "железе", дело никогда не доходит. Другое дело - программирование. В нем каждый имеет возможность проектировать, создавать и пользоваться в реальном виртуальном мире своего компьютера инженерными конструкциями собственного приготовления. Доступность, дешевизна, гибкость, практическая значимость ставят программирование вне конкуренции как полигон для подготовки инженера или исследователя в любой области техники - ведь принципы инженерного искусства везде одни и те же. В этом смысле рядом с программированием можно поставить разве что электронные конструкторы типа Arduino. Но последние и сложнее, и специфичнее, и дороже.

Цель курса - в общедоступной форме изложить философию и некоторые принципы инженерного искусства на примере программирования.

К сожалению, чем глубже вы будете изучать Python и его библиотеки и чем более сложные задачи будете ставить, тем большее количество технической информации придется усваивать. Это неизбежно. Из-за этого наш мир заполнен узкими специалистами, хорошо знающими только свою специальность.

Желание понизить планку вхождения в этот курс определило его задачу - быстро научить будущего или уже состоявшегося инженера или ученого использовать библиотеки Python в своей обычной работе: для построения графиков, проведения численных расчетов и т.п. Python - один из самых простых для освоения современных языков программирования, очевидный кандидат на замену Pascal в системе образования. Мой педагогический опыт показывает, что студенты вполне способны овладеть технической стороной этого курса, имея лишь опыт программирования на Паскале в школе.

Если говорить о методике обучения, то в заданиях курса практически не требуется писать код "с нуля", "с чистого листа". Вместо этого в качестве исходной точки любой задачи берется уже готовый код, который нужно переделать, дополнить или расширить. Такой подход гораздо эффективнее и ближе к реальной жизни.

Курс базируется на свободном программном обеспечении и сам защищен свободной лицензией Creative Commons.

Установка библиотек Python. Дистрибутив Anaconda. Portable Python 2.7

Сила Python - в его "внешних" библиотеках, неизмеримо расширяющих возможности языка. На сегодняшний день число только самых интересных, обязательных для изучения библиотек Python - явно больше 10. Все они требуют отдельной установки, зависят от тех или иных версий других библиотек и, бывает, конфликтуют друг с другом. Чтобы избавить пользователя от этих технических проблем, стали создавать дистрибутивы Python, включающие сам язык и его библиотеки. Они напоминают дистрибутивы Linux, если кто с ними сталкивался.

Один из наиболее популярных - это дистрибутив Anaconda (300-500 Мбайт), существующий для языков Python 2 и 3 для 32-разрядной и 64-разрядной архитектуры. Установка происходит не так быстро, как хотелось бы.

Другой вариант, который рекомендуется в этом курсе - это использование переносимого дистрибутива Portable Python-2.7.17. Его главное достоинство - нет нужды в установке, можно просто скопировать папку с файлами языка Python на свой компьютер и сразу начинать работать. Все нужные для работы с этой книгой библиотеки в нем уже есть. Если требуется какая-то другая, отсутствующая в дистрибутиве библиотека, можно попытаться установить ее через программу pip. Как это делать описано в текстовом файле how to use PIP.txt в основном каталоге Portable Python.

Недостатки у такого подхода тоже есть: язык Python 2 больше не поддерживается, для него не выпускаются новые версии библиотек. Но для образовательных целей возможностей Python 2 более чем достаточно: это зрелый язык программирования с колоссальными возможностями. Прекращение его разработки можно воспринимать даже как определенное преимущество: однажды написанный код всегда будет совместим с последней версией Python 2. Для переноса ваших скриптов на другой компьютер достаточно скопировать туда каталог с кодом и с самим Portable Python.

Замечание. Работая с Python 2, не используйте в названиях файлов и каталогов кириллические символы!

Литература

  1. Свободные программы для Windows (Ф.Занько)
    Краткая история концепции свободного программного обеспечения, размышления о его роли и перспективах применения в образовании и науке, а также список лучших свободных программ для Windows, которые уже сегодня могут восполнить основные нужды среднего пользователя персонального компьютера. Этот материал обсуждался на Второй конференции "Свободное программное обеспечение в высшей школе" (Переславль-Залесский, 26-28 января 2007 г.), проведенной российской компанией "Альт Линукс".

Лучшее враг хорошего или If it ain't broke, don't fix it

Говорят, что Берт Ланс, директор Отдела управления и бюджета в администрации американского президента Джимми Картера, считал, что можно сэкономить миллиарды для Дяди Сэма, если убедить правительство следовать простому правилу: "Не чини того, что работает" (If it ain't broke, don't fix it). "У нашего правительства, - толковал он,- есть проблема: оно чинит вещи, которые работают, и не чинит вещи, которые не работают" [Newsletter of the US Chamber of Commerce, Nation's Business, May 1977].

История с переходом на Python 3 - яркая иллюстрация этого простого принципа. Гвидо ван Россум и его команда разработчиков Python выпустили в 2008 г. версию Python 3.0, которая была полностью несовместима с предыдущими версиями языка. Разработка Python 2 была прекращена в 2010 г. на версии 2.7, всем пользователям было предложено переходить на Python 3.

Каких-то неразрешимых проблем у Python 2 не было. Это был и есть состоявшийся, удобный и надежный язык программирования со своими достоинствами и недостатками, завоевавший в свое время популярность среди миллионов любителей и профессионалов. На нем было написано огромное количество работающего кода, в том числе коммерческого. И вдруг людям было предложено заняться переносом этого кода, тратить на это время, деньги, силы, заново его отлаживать. Не удивительно, что переход на Python 3 в действительности до сих пор не состоялся несмотря на все заклинания "великодушного пожизненного диктатора" и пропагандистов фонда Python Software Foundation о том, что Python 2 - это история, а Python 3 - настоящее и будущее Python. Так, по некоторым данным в 2017 году почти 64% новых (!) коммерческих проектов на Python делались на версии 2.7 (в 2016 г. их было ок. 69%).

Проблема заключается в том, что Python 3 по факту - это не Python, а совершенно другой, только похожий на Python, язык. Более того, Python 3 имеет не только свои преимущества перед Python 2, но и недостатки. Критический профессиональный взгляд на проблему перехода с Python 2 на Python 3 представлен в статьях "Мысли о Python" и "Катастрофа Unicode в Python3" Армина Ронахера.

Можно понять Гвидо ван Россума - у него появились новые идеи, которые нельзя было реализовать в рамках Python. Правильно было бы объявить о начале разработки нового языка, параллельно поддерживая Python 2, как это было сделано с Perl 6. Но тогда нынешний Python 3 скорее всего пополнил бы большой список красивых языков, которые никому не нужны. Гораздо интереснее сказать, что Python 2 устарел и всеми правдами и неправдами заставить людей перейти на Python 3, что в принципе и делается. Интернет забит пропагандой Python 3. Авторитет Гвидо так велик, что с ним трудно и неудобно спорить. Мне самому неприятно писать эти строки. Поэтому большинство просто молчаливо или виновато оправдываясь саботирует переход на третий Python.

Конечно, и Python 3 - это неплохой язык со своими удобствами и проблемами. Новичку почти безразлично, какую версию Python изучать. Если бы Гвидо ван Россум был обычным разработчиком языков программирования, никаких проблем бы не было: мало ли ошибок делают разработчики? Но за ним стоят не только люди, непосредственно разрабатывающие Python, но и миллионы простых пользователей, а также коммерческие компании, выбравшие Python в качестве своего основного инструмента. Сообщество Python оказалось расколото; оно понесло убытки, тратя время и деньги на перевод уже готового кода на другой язык; разработчики библиотек вынуждены тратить дополнительные ресурсы, чтобы их код поддерживал и Python 2.7 и Python 3; Python теперь не имеет единой общепризнанной стандартной версии, что затрудняет его внедрение, скажем, в области образования; развитие сообщества Python затормозилось. Такова цена одной ошибки великого программиста.

P.S. "Кстати, вот интересная вещь. Есть такой язык, Tcl. Так вот, несмотря на то, что он постоянно развивается, API меняются таким образом, что минимально ломают обратную совместимость, а чаще всего не ломают совсем. Причём, как на уровне Tcl, так и на уровне C. С большой вероятностью C-расширение, написанное для бородатой версии Tcl, можно с полпинка завести на свежем срезе development-версии. Если же речь идёт о коде на Tcl, то 90% кода работать будет просто сразу, без модификаций, только быстрее :)" [Один из комментариев к статье "Мысли о Python"]

Python в роли калькулятора

Самый простой способ начать работу с Python из дистрибутива Anaconda (на примере Windows 7) - нажать кнопку Пуск, в появившемся поле "Найти программы и файлы" ввести слово "idle" и нажать клавишу Enter (рис.0.1). В Portable Python для того же самого нужно запустить файл IDLE-Launcher.exe из главного каталога.

Рис.0.1. Запуск IDLE

Перед вами должно появиться окно IDLE (рис.0.2). Что такое IDLE? Это так называемая интегрированная среда разработки (Integrated Development Environment), разработанная создателями Python для облегчения программирования. IDLE полностью написана на языке Python, ее код можно посмотреть и при желании внести в него изменения.

Рис.0.2. Окно командной строки IDLE

Это одно из двух основных окон IDLE, с которыми вам предстоит работать. Его называют окном интерпретатора или окном командной строки. У интерпретатора есть замечательное свойство: как только будет введена команда, Python тут же исполнит ее и выведет на экран полученный результат. Фактически перед вами очень мощный и удобный калькулятор!

Попросим Python что-нибудь напечатать, например традиционную фразу: "hello world".

Рис.0.3. Первый диалог с интерпретатором Python: hello, world

Значки '>>>' играют роль приглашения: Python сигнализирует, что готов считывать новую команду. Также, обратите внимание, после ввода команды Python тут же выводит что получилось в результате ее выполнения.

Попробуем еще несколько команд. Посмотрите на рис.0.4:

Рис.0.4. Первый диалог с интерпретатором Python: простейшие вычисления

на нем показан результат запуска новых команд. Не слишком беспокойтесь о том, как правильно программировать: сейчас мы экспериментируем с Python, вводя в него команды. Если что-то не работает, исправляем ошибку и пробуем снова.

Хорошо, теперь зададимся вопросом: если закрыть Python и снова запустить его, как компьютер вспомнит, что мы напечатали? Никак. Нельзя напрямую сохранить содержимое окна интерпретатора, потому что в него входят и сами команды, и ответы системы, например значки '>>>' . Вместо этого мы создадим файл, в котором будут только команды, и сохраним его как документ с расширением *.py. Этот файл всегда можно открыть и запустить в Python, экономя время на повторном наборе всех его команд.

Попробуем. Начнем с чистого листа, открыв новое окно (рис.0.5).

Рис.0.5. Как открыть окно программ

Как видно, в новом окне ничего нет (рис.0.6) - оно целиком и полностью отдано под команды. Теперь Python не будет прерывать вашу работу с программой, вернее, пока вы не скажете ему это сделать. Чтобы не путать с окном интерпретатора, назовем его "окном программ".

Рис.0.6. Новое окно программ

Все, что мы хотели сделать,- это сохранить несколько строк, уже опробованных в окне интерпретатора. Реализуйте этот план, скопировав/вставив эти команды в окно программ (рис.0.7). Не забудьте при этом удалить приглашения ">>>", потому что они в программу не входят. Интерпретатор использует их, чтобы напомнить, что вы работаете в интерпретаторе. Но сейчас при редактировании отдельного файла эти артефакты интерпретатора совершенно ни к чему.

Рис.0.7. Окно IDLE с текстом программы

Запускаем файл на выполнение: находим в главном меню пункт Run, подпункт Run Module или просто нажимаем быструю клавишу F5 (рис.0.8).

Рис.0.8. IDLE предлагает сначала сохранить сделанную работу

Что-то пошло не так? Нет, просто нас застало врасплох правило IDLE сохранять любое окно с программой, прежде чем запустить ее. Это вопрос организации интерфейса пользователя. IDLE хочет убедиться, что вы не забыли сохранить свою работу, перед тем как начнете ее проверять в деле. Что ж, жмем OK и вводим имя нового файла. Еще раз F5 - и новая напасть: IDLE не нравятся русские буквы в тексте программы и вам предлагается явно задать кодировку (рис.0.9).

Рис.0.9. IDLE предлагает явно задать кодировку

Реакция IDLE из Portable Python будет несколько иной: он все напечатает, не задавая лишних вопросов, но не справится с русскими буквами.

Вопросы отображения символов, выходящих за пределы стандартного набора латинских символов ASCII, - это большая тема в Python. Сейчас нет смысла в нее влезать. Можно согласиться с предложением IDLE и позволить ей самой отредактировать ваш файл, согласившись добавить строку "# -*- coding: cp1251 -*-". В Portable Python ее нужно ввести вручную. Более универсальный вариант, которым я рекомендую пользоваться в будущем, - это выбор кодировки utf8 (юникод) вместо cp1251. Но пока сойдет и так: жмем Edit my file и снова F5.

Рис.0.10. Синтаксическая ошибка

А вот теперь дело серьезнее - синтаксическая ошибка! Python сигнализирует о нарушении грамматических правил языка (рис.0.10). Что там подсвечено красным? Ну, конечно, - пропущена закрывающая кавычка! Исправляем и еще раз F5.

Рис.0.11. Окно командной строки (интерпретатора) с результатами выполнения программы

Наконец-то! Появляется наш старый знакомый - окно интерпретатора с результатами выполнения программы (рис.0.11). Все в порядке.

В заключение убедимся, что созданный вами файл можно будет загрузить снова. Закрываем все окна IDLE и начинаем с чистого листа. Найдите команду Recent Files (последние файлы) в меню File: появится список, в котором на первом месте - ваша новая программа. Выберите ее, и она появится в окне программ.

Итак, вы овладели начальными навыками работы с Python. Теперь можно применить их в деле. Попытаемся использовать окно командной строки IDLE в роли калькулятора.

Начнем с простого:

Рис.0.12. Деление двух целых чисел

Что за дела, почему неправильный результат? Дело в том, что для Python число, записанное без десятичной точки, - это особый тип данных, так называемое целое число, которое не может иметь дробной части. Мы еще со школы привыкли не различать в записи целые и вещественные числа, но для компьютера это совершенно разные вещи. К этому нужно отнестись внимательно, чтобы избежать возникновения неожиданных ошибок при программировании вычислений.

Если тип чисел, над которыми производятся математические операции, не один и тот же, целое число будет автоматически преобразовано в вещественное. Для этого достаточно поставить у одного из чисел десятичную точку или экспоненту (рис.0.13).

Рис.0.13. Автоматическое преобразование типа числа

А какое максимальное целое число способен воспринять интерпретатор Python? Узнать это можно с помощью специальной функции maxint из библиотеки Python sys. Прежде чем вызывать функцию, ее нужно из библиотеки импортировать (рис.0.14). Библиотеку sys отдельно устанавливать не нужно - это фактически часть стандартного языка Python. Ее можно назвать "внутренней" библиотекой в отличие от других - "внешних" библиотек, которые, прежде чем использовать, приходится скачивать в Интернете и устанавливать, как обычную программу Windows. На следующих занятиях мы будем иметь дело с целым рядом таких библиотек, но работу по их установке, как правило, берет на себя дистрибутив Anaconda. В Portable Python все нужные нам библиотеки уже есть.

Рис.0.14. Максимальное целое число, поддерживаемое интерпретатором Python

В данном случае это число равно 231-1. На другом компьютере оно может быть другим. Заметьте, что две звездочки подряд (**) означают в Python возведение в степень.

А как быть, если нужно работать с числом, большим чем maxint? Попробуем получить число, состоящее из единицы и ста нулей, - знаменитый гугол. В честь этого числа названа компания Google. Введем в командную строку Python команду:
>>> 10**100 [Enter]

Рис.0.15. Гугол

Что ж, все работает, а справа от числа появилась заглавная L. Оказывается, когда заканчиваются целые числа, Python автоматически переходит на другой тип данных - так называемые длинные (long) целые. Символ L справа именно об этом и сигнализирует. Так что на наш век чисел хватит.

Два слова о стандартных математических функциях, таких как sqrt, log, log10, exp, sin, cos, tan, arcsin, arccos, arctan, sin, cosh, а также константах pi и e: они не относятся к базовой части языка, а сосредоточены в отдельном модуле math. Поэтому, прежде чем использовать, их нужно импортировать, как мы это уже делали с функцией maxint. Импортировать функции можно по отдельности:

Рис.0.16. Импортирование функций из модуля math по отдельности

или группами:

Рис.0.17. Импортирование функций из модуля math группами

или же возможно импортировать сразу все содержимое модуля:

from math import *

Также имеется возможность импортировать сам модуль:

import math

и использовать "расширенные" названия функций: math.sqrt, math.exp и т.д.

Задание

Решить один из приведенных ниже примеров тремя способами: сначала вручную (все вычисления столбиком должны быть записаны на листочке, арифметические ошибки допустимы, если они есть - перерешивать не нужно), затем с помощью стандартного калькулятора Windows или на телефоне, потом с помощью Python. Какой способ проще лично для Вас? Почему?

Примечание. В этих примерах необычный знак умножения - он выглядит как обычная точка. Так писали в старые времена. Примеры взяты из дореволюционного задачника.

Вопросы

  1. Сталкивались ли вы с окном интерпретатора в Паскале?

  2. Попробуйте, работают ли клавиатурные комбинации для работы с буфером обмена (CTRL-C, CTRL-X, CTRL-V) в IDLE с включенной русской раскладкой.

Литература

  1. Забавы с IDLE: день первый (Danny Yoo)
    Очень простое введение в программирование на Python. IDLE - это стандартная интегрированная среда разработки Python, полностью написанная на Python/Tk.
  2. Как использовать IDLE (для версии 0.5) (Daryl Harms)
    Устаревшее описание возможностей среды IDLE. Тем не менее, оно до сих пор полезно для обучения. Части документа, не представляющие интереса для тех, кто пользуется современными версиями Python, зачеркнуты.
  3. Документация IDLE
    Документация IDLE в версии Python 2.6.5. Фактически - это справочник команд.

1. Число

Что такое программирование и почему оно важно

Определить, что такое программирование, не так просто. Обычно говорят, что это процесс создания компьютерных программ. Программа - это последовательность шагов для достижения цели. Определение "компьютерная" подчеркивает, что речь идет о программе, предназначенной для компьютера. Осталось понять, что такое компьютер. Согласно Википедии, это устройство для выполнения программ. Логический круг замкнулся. Попробуем еще раз, зайдя с другой стороны.

Computer по-английски означает "вычислитель". Конечно, любой человек скажет, что компьютер не только вычисляет, но и переводит с одного языка на другой, играет в шахматы, управляет работой станков и т.п. Тем не менее, на самом глубоком уровне (на уровне машинных кодов) любой компьютер является всего лишь вычислителем. Мощным, быстрым, ничего не забывающим, но вычислителем. Поэтому программирование, каким бы ни было разнообразным его применение, - это не более и не менее, чем математика - искусство обращения с числами. Компьютер, если угодно,- своего рода усилитель математических способностей человека. Как электронный усилитель с колонками делает громче человеческий голос, так компьютер расширяет возможности применения математики, как науки о количественном аспекте природы.

Теперь обратимся к другому вопросу: почему программирование играет такую важную роль в нашей технической цивилизации? Программист в наши дни - гораздо более уважаемая и лучше оплачиваемая профессия, чем, скажем, фермер, хотя без программ человек может жить, а без еды - нет. Для ответа нужно разобраться, почему математика (и программирование) так эффективны для описания многих явлений нашего мира.

Это непростая проблема, занимавшая многие великие умы. Обзор разных точек зрения по этой теме можно найти в книге Морриса Клайна "Математика. Поиск истины" [Клайн М. Математика. Поиск истины.- М.: Мир, 1988.- 295 с.]. Хороша статья нобелевского лауреата по физике Юджина Вигнера "Непостижимая эффективность математики в естественных науках" [Вигнер Е. Непостижимая эффективность математики в естественных науках // Успехи физических наук.- 1968.- Т.94.- Вып.3.- С.535-546].

Моя точка зрения заключается в том, что ответ был дан еще пифагорейцами и следовавшими за ними философами древней Греции. Пифагор считал, что сущность всех вещей - в числе. Организация вселенной есть гармоническая система чисел и их отношений. Говоря современным языком, многим явлениям природы присущ количественный аспект. Не всем (исключения - жизнь, душа, мысль и т.д.), но очень многим. Даже разные цвета и звуки отличаются друг от друга численно - длиной волны. Молекулы разных веществ состоят из одних и тех же протонов, нейтронов, электронов, а отличаются друг от друга - их числом. Наконец, материя как таковая - тоже число:

"Мы теперь знаем то, что надеялись найти древние греки, а именно, что действительно существует только одна основная субстанция, из которой состоит все существующее. Если давать этой субстанции наименование, то ее можно назвать не иначе, как "энергия". Но эта субстанция - энергия - может существовать в различных формах. Она всегда проявляется дискретными порциями, которые мы рассматриваем как мельчайшие неделимые составные элементы всех веществ и которые по чисто историческим соображениям называются не атомами, а элементарными частицами. Из основных форм энергии три формы отличаются особенной устойчивостью: электроны, протоны и нейтроны. Материя в собственном смысле слова состоит из этих форм энергии... Многообразие явлений нашего мира создается, подобно тому как это предвидели греческие натурфилософы, многообразием форм проявления энергии. А эти формы, если мы хотим их понять, необходимо, в свою очередь, представить в математических образах, в конечном счете, просто посредством совокупности решений системы уравнений" [Гейзенберг В. Философские проблемы атомной физики.- М.: Издательство ЛКИ, 2008.- С.98-99].

На чисто математическом характере понятия энергии настаивал и Ричард Фейнман в своих знаменитых "Лекциях по физике":

"Существует факт, или, если угодно, закон, управляющий всеми явлениями природы, всем, что было известно до сих пор. Исключений из этого закона не существует; насколько мы знаем, он абсолютно точен. Название его - сохранение энергии. Он утверждает, что существует определенная величина, называемая энергией, которая не меняется ни при каких превращениях, происходящих в природе. Само это утверждение весьма и весьма отвлеченно; это по существу математический принцип, утверждающий, что существует некоторая численная величина, которая не изменяется ни при каких обстоятельствах. Это отнюдь не описание механизма явления или чего-то конкретного, просто-напросто отмечается то странное обстоятельство, что можно подсчитать какое-то число и затем спокойно следить, как природа будет выкидывать любые свои трюки, а потом опять подсчитать это число - и оно останется прежним... Важно понимать, что физике сегодняшнего дня неизвестно, что такое энергия. Мы не считаем, что энергия передается в виде маленьких пилюль. Ничего подобного. Просто имеются формулы для расчета определенных численных величин, сложив которые, мы получаем число 28 - всегда одно и то же число. Это нечто отвлеченное, ничего не говорящее нам ни о механизме, ни о причинах появления в формуле различных членов" [Фейнман Р., Лейтон Р., Сэндс М. Фейнмановские лекции по физике. 1. Современная наука о природе. Законы механики. 2. Пространство. Время. Движение.- М.: Мир, 1976.- С.72,74].

Правду сказать, у пифагорейцев в новое время сложилась не слишком хорошая репутация:

"Но самымъ уродливымъ уклоненіемъ нашей науки съ ея истиннаго пути было то, когда вмѣсто вычисленій и дѣйствій ученые занимались классификаціей чиселъ и открытіемъ ихъ таинственныхъ свойствъ. А стремленіе къ такимъ занятіямъ не разъ прорывалось наружу, особенно у людей, настроенныхъ мистически. Среди нихъ первое мѣсто занимаетъ греческій философъ Пиѳагоръ и его послѣдователи. Онъ жилъ за 500 лѣтъ до Р.X. въ знаменательное время, когда приблизительно жили и дѣйствовали основатели новыхъ религій, Зороастръ въ Персіи и Конфуцій въ Китаѣ. То было мистически настроенное время, и Пиѳагоръ оказался усерднымъ его дѣтищемъ, такъ какъ вникалъ въ числа и искалъ въ нихъ ихъ внутренняго смысла. Онъ искалъ священныхъ чиселъ и выше всего ставилъ число 36, какъ символъ "всей вселенной", на томъ основаніи, что число 36 равно суммѣ первыхъ четырехъ четныхъ и первыхъ четырехъ нечетныхъ чиселъ: 36=1+3+5+7+2+4+6+8; числомъ 36 пользовались ученики Пиѳагора, какъ торжественной формулой клятвы. Число 9 было у нихъ символомъ постоянства, такъ какъ всѣ кратныя 9-ти имѣютъ суммой цифръ все-таки 9, именно: у дважды девяти, т.-е. у 18, сумма цифръ 1+8=9, у трижды девяти, т.-е. у 27-ми, 2+7=9, у 36-ти 3+6=9 и т.д. Число восемь было символомъ смерти, потому что кратныя 8-ми, т.-е. 16, 24, 32, 40 имѣютъ все меньшую и меньшую сумму цифръ: 7, 6, 5, 4. Единица, по Пиѳагору, обозначала духъ, изъ котораго проистекаетъ весь видимый міръ. Изъ единицы происходитъ двойка, символъ матеріальнаго атома. Принимая въ себя опять единицу, двойка, или матеріальный атомъ, становится тройкой или подвижной частицей. Это символъ живого міра. Живой міръ плюсъ единица, слѣдовательно, четверка, образуетъ цѣлое, т.-е. видимое и невидимое. Такъ какъ 10=1+2+3+4, то оно выражаетъ собою "Все". Пиѳагорейцы провозглашали число началомъ и основаніемъ всѣхъ вещей, такъ какъ, по ихъ словамъ, природа числа не допускаетъ никакого обмана, она закономѣрна и неизмѣнна, она проникаетъ въ неизвѣстное.

Такими-то хитросплетенными умствованiями занимались пиѳагорейцы..." (Беллюстин В. Как постепенно дошли люди до настоящей арифметики).

Не слишком-то лестная характеристика, как видно. Но вот как оценивал философское наследие последователей Пифагора один из создателей современной атомной физики Вернер Гейзенберг:

"Абстрактность современного понятия атома и математические формы, которые в современной атомной теории служат для выражения разнообразия явлений, приводят нас ко второй основной идее, воспринятой современным точным естествознанием из античности: убеждению в творческой силе математических построений.

Впервые в ясно выраженной форме эта идея встречается в учении пифагорейцев, причем она проявляется здесь в открытии математических условий гармонических колебаний. Исследуя колебания струн, пифагорейцы нашли, что две приведенные в колебание струны дадут гармоническое созвучие, когда (при прочих равных условиях) их длины будут находиться в простом рациональном отношении. Это означает, что суммарный звук воспринимается человеком как гармонический только в том случае, если в нем реализованы некоторые простые математические отношения, хотя сам слушатель может и не сознавать этого. Данное открытие представляет собой один из сильнейших импульсов для развития науки вообще, ибо кто хотя бы один раз убедился в творческой силе математических построений, тот будет замечать их действие на каждом шагу как в области природы, так и в области искусства. В качестве особенно простого и наглядного примера следует упомянуть калейдоскоп, в котором посредством простой математической симметрии из чисто случайного возникaeт нечто имеющее смысл и красоту. Более ценные и важные примеры может дать анализ произведений искусства или (в приpоде) изучение кристаллов. Если в основе музыкальной гармонии или форм изобразительного искусства обнаруживается математическая структура, то рациональный порядок окружающей нас приpоды должен иметь свою основу в математической сущности законов природы. Такое убеждение впервые нашло свое выражение в пифагорейском учении о гармонии сфер и в том, что элементам были присвоены правильные формы. В "Тимее" Платон рассматривает атомы земли, огня, воздуха и воды соответственно как кубы, тетраэдры, октаэдры и икосаэдры. В конечном счете, на таком убеждении основано все математическое естествознание.

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

Эти изменения постольку представляют собой последовательное осуществление программы пифагорейцев, поскольку бесконечное разнообразие явлений природы находит свое правильное математичеокое отражение в бесконечном числе решений одного уравнения, например дифференциального уравнения механики Ньютона. Требование, согласно которому из одного уже сформулированного закона природы должно быть выведено бесконечное множество явлений, доступных экспериментальному исследованию, дает в то же время гарантию правильной и, следовательно, справедливой на все времена формулировки закона. Уравнение, формулирующее такой закон, выражает прежде всего только простейшие физические условия: оно определяет динамические понятия, необходимые для осмысления рассматриваемых явлений природы. Кроме того, это уравнение содержит некоторые общие высказывания, касающиеся мира наших восприятий, напримeр, указание на тот факт, что в пустом пространстве нельзя определить положение и направление. Тем не менее из него можно получить, как возможное следствие, бесконечное множество явлений, подобно тому как несколько тактов музыкальной темы могут быть развиты до сложной фуги. Таким образом, если древняя философия приписывала атомам элементов правильные геометрические формы, то с элементарными частицами современной физики связывается математическое уравнениe. Это уравнение формулирует закон природы, определяющий строение материи. Оно содержит в себе процессы, совершающиеся во времени, например химическую реакцию, а также правильные формы кристаллов или тоны колеблющейся струны. Исходя из случайных начальных условий, оно закономерно выводит физические явления окружающего нас мира, подобно тому как калейдоскоп создает замысловатые узоры из случайного сочетания цветных стекол.

Результаты такого рассмотрения явлений природы неожиданным образом подтвердили воззрения пифагорейцев, частично обусловив реальное господство над силами природы и оказав решающее влияние на развитие человечества. Поэтому вера в простую математическую сущность всех закономерных взаимосвязей природы (в том числе и тех, о которых мы еще не подозреваем) настолько жива также и в современной наукe, что математическая простота считается высшим эвристическим принципом при отыскании законов природы в открывающейся благодаря новым экспериментам области. В новой области опыта внутренние взаимосвязи впервые становятся понятными лишь тогда, когда удается математически просто сформулировать господствующие в данной области законы" [Гейзенберг В. Философские проблемы атомной физики.- М.: Издательство ЛКИ, 2008.- С.50-53].

Апофеозом, подлинным триумфом пифагорейского подхода к естествознанию стала современная атомная физика, в которой человек столкнулся с реальностью, для познания которой у него не осталось никакого другого инструмента кроме математики. Атом - то, из чего состоит вся материя,- превратился почти в "голую идею", в уравнение; без свойств, без определенного положения в пространстве, не дозволяющий никаких интуитивных представлений о себе.

"Как известно, атомная физика, развивавшаяся на основе этих представлений под руководством Бора в течение последних двадцати лет и пока еще не вполне завершенная, охватывает уже теперь необычайно широкую область опытных знаний. Например, ею дается математически формальная сущность всех химических закономерностей: достаточно указать, что в принципе атомная физика дает возможность определить цвета всех простых веществ. Программа Демокрита, таким образом, здесь в значительной мере реализована - видимые качества материи сведены к конфигурационным свойствам атомов.

Однако современная атомная физика в одном пункте идет значительно дальше атомистического учения древних греков, причем это имеет существенное значение для понимания всего ее развития. Согласно Демокриту, атомы были лишены качеств, подобных цвету, вкусу и т.д.; они обладали лишь свойством заполнять пространство. Геометрические же высказывания относительно атомов рассматривались как вполне допустимые и не требовали какого-либо дальнейшего анализа. В современной физике атомы теряют и это последнее свойство: они обладают геометрическими качествами не в большей степени, чем остальными - цветом, вкусом и т.д. Атом современной физики может быть лишь символически представлен дифференциальным уравнением в частных производных в абстрактном многомерном пространстве; только эксперименты наблюдателя вынуждают атом принимать известное положение, цвет и определенное количество теплоты. В современной физике для атома все качества являются производными; непосредственно он не обладает никакими материальными свойствами. Это означает, что любая картина атома, которую можно нарисовать на основе наших представлений о нем, будет ео ipso [тем самым] ошибочной. Объяснение "первого рода" (я бы сказал почти: per definitionem [по определению]) невозможно для мира атомов. Это развитие кажется нам последовательным во всех отношениях. Прежде всего, оно восстанавливает равновесие между различными свойствами материи, которое было утеряно в старой атомистической теории; геометрические свойства не имеют теперь преимущества перед другими свойствами. Как подчеркнул Бор, теперь уже неправильно считать, что качества тел сводимы к геометрии атомов. Наоборот, знание цвета тела становится возможным только при условиях отказа от познания движения атомов и электронов внутри этого тела, а познание движения электронов, в свою очередь, заставляет отказаться от знания цвета, энергии и температуры. Оба случая сводимы, если хотите, только к математике атома. В современной атомной теории ни одно из чувственно данных свойств тел не принимается, не будучи проанализированным, и не переносится автоматически на мельчайшие частицы материи. Скорее, каждое свойство анализируется для целей διάνοια. Отсюда как естественное следствие вытекает, что атомы не могут обладать в обычном смысле ни одним из этих свойств. Из рассмотрения механики и оптики Ньютона уже можно видеть, что сила этого абстрактного развития науки о природе лежит прежде всего в ее способности охватывать простым образом обширные области опыта и непрерывно все более упрощать и унифицировать рисуемую наукой картину природы. Что атoмная физика дала в этом отношении блестящие результаты, показывают нам яснее чем когда-либо успехи последних лет. Мы не можем без восхищения пройти мимо того факта, что бесконечное разнообразие явлений природы, на Земле и на звездах, могут быть систематизированы в такой простой схеме законов. С другой стороны, не следует забывать, что такая унификация естественно-научной картины мира стоила очень дорого: прогресс в науке о природе был куплен ценой отказа от того, чтобы при помощи естествознания представить явления природы в их непосредственной жизненности" [Гейзенберг В. Философские проблемы атомной физики.- М.: Издательство ЛКИ, 2008.- С.31-33].

Эти размышления подводят к очень важным философским выводам. Главное свойство числа, его суть - это упорядоченность. Действительно, возьмем произвольный набор чисел: их всегда можно расположить по порядку и притом единственным образом. Значит, все творение, вся материя на всех уровнях в высшей степени упорядоченны. В нашем мире случайности нет, а есть превосходящая человеческое разумение сложность. Так, случайное распределение событий Гаусса на самом деле не случайное, а порождается чрезвычайно большим (в математике упрощенно говорят: бесконечно большим) числом действующих причин.

Итак, все виды движения и сама материя - это разные проявления энергии, которая выражается в виде числа. Неудивительно, что математика, занимающаяся числами во всех их проявлениях, так хорошо подходит для описания определенных свойств нашего мира в количественном аспекте.

Как понимать последнюю фразу? Если бы математика полностью описывала все, то с помощью математических моделей мы могли бы в точности предсказывать будущее и управлять им. Но: "Окружающий нас мир поразительно сложен, и самая очевидная истина заключается в том, что мы не в состоянии предсказать его будущее" (Вигнер Е. Непостижимая эффективность математики в естественных науках). И тем не менее есть область жизни, где мы можем предсказывать и даже конструировать будущее с помощью математики:

"... законы природы можно использовать для предсказания будущего лишь в исключительных обстоятельствах, а именно лишь тогда, когда известны все существенные (для предсказания будущего) условия, определяющие состояние мира в данный момент. Отсюда же следует, что создание машин, функционирование которых физик может предвидеть заранее, является наиболее эффектным его достижением. В этих машинах физик создает ситуацию, при которой все существенные параметры известны и поведение машины предсказуемо. Примерами таких машин могут служить радары и ядерные реакторы" (Вигнер Е. Непостижимая эффективность математики в естественных науках).

Механизмы, техника во всем своем многообразии - вот сфера, где человек чувствует себя богом. Инженер, зная законы природы, может предсказать, как будут работать создаваемые им устройства. И программирование является важной частью этого искусственного мира, создаваемого человеком на теле природы.

Модели и алгоритмы

Мы выяснили, что все материальное, все, что изучает физика, может быть описано числами. Физическая реальность и число - это не одно и то же, но число в определенном смысле выражает одну из сторон реальности, может быть даже ее суть. В физике все реальные вещи заменяются числами, для физика весь мир - это набор чисел.

Наш физический мир представляет собой единое целое, все его составляющие - от элементарных частиц до звезд - связаны друг с другом. Числа, отражая реальность, также не являются изолированными, отделенными друг от друга; напротив, все они тем или иным образом связаны друг с другом.

Связи между явлениями реального мира часто очень сложны. Так, физики до сих пор не понимают природу гравитации, человеческое воображение ничем не может помочь при описании явлений микромира и т.п. Но связь между числами, описывающими реальность с количественной стороны, намного проще и может быть выражена математическими соотношениями, которые принято называть физическими законами, например законом всемирного тяготения или уравнением Шрёдингера.

Таким образом, научное изучение какого-нибудь физического явления фактически означает получение математических соотношений, связывающих числа, описывающие это явление.

Как же находят эти математические соотношения? Это непростой и увлекательный процесс, доступный только живым разумным существам и то не всем. ☺ Мысль, как и число, - не материальная, а идеальная сущность. [Это не очень популярная точка зрения последние лет 200. "Современный "миф о материи" видит в сознании нечто иное, чем вещество, хотя при этом утверждает, что бытие исчерпывается материей. Образовавшееся противоречие он пытается преодолеть "теорией отражения", которая на самом деле предлагает вместо решения сомнительную метафору, взятую из оптики" (Мень А. В поисках Пути, Истины и Жизни. Т.4.: Дионис, Логос, Судьба: Греческая религия и философия от эпохи колонизации до Александра.- М.: ИД "Жизнь с Богом", 2009.- 384 с.). Гораздо последовательнее был предтеча всех современных материалистов - Демокрит из Абдеры. Он попросту считал, что никакого духа нет, а мысль есть лишь скопище атомов, только гладких и круглых, похожих на атомы огня. ☺ На самом деле признание мысли проявлением духа - гостя, пришедшего в материальный мир свыше, значительно все упрощает и расставляет на свои места.] Мышление - тоже своего рода моделирование окружающего мира, но более универсальное, чем математика. Для живой мысли мир - это не только количество. Результатом доведенной до конца мыслительной деятельности является математическое соотношение, описывающее связь между числами - идеальными, упрощенными образами реальных материальных явлений.

Какое же место в деле познания природы занимает компьютер? Фактически он представляет собой механическую [не важно, что современные компьютеры работают на электричестве: это вопрос выбора технологии; точно так же можно было бы использовать чисто механические устройства - принципиально ничего не поменялось бы] модель числа и операций над числами.

Очень важно, что речь идет о механической модели чисел, логических и арифметических операций, а не о моделировании процесса мышления. Мы умеем выражать мысли с помощью слов, образы - создавая произведения искусства, но все это - завершенный, уже готовый продукт мыслительной деятельности. Мыслить механические модели не смогут никогда, потому что воспринимать идеальные объекты (мысли, образы, числа) может лишь живой разум. Фантастические истории про восстание машин в духе "Терминатора" не возможны, пока роботы не будут запрограммированы извне злым живым разумным существом.

Обычный человек делится своими мыслями, произнося слова; художник "говорит" с помощью своих картин; математик свои рассуждения оформляет в виде алгоритмов. Алгоритм - одно из важнейших понятий современной математики. Как и в случае другого столь же фундаментального понятия - доказательства, строгого определения алгоритма нет [Успенский В.А. Машина Поста.- М.: Наука, 1988.- 96 с.]. Взамен этого в литературе можно обнаружить ряд описаний алгоритма:

Итак, изучая объекты материального мира, ученые заменяют их идеальными сущностями - числами и дальше работают уже только с ними. Разум - орган, предназначенный для работы с идеальными объектами - мыслями, образами, числами, - пытается решить математическую задачу. В случае успеха готовое решение излагается в виде алгоритма. Далее числа и вычисления, прописанные в алгоритме, могут быть смоделированы с помощью вычислительной машины. Последний шаг есть собственно программирование.

Рассмотрим для ясности классический пример алгоритма, знакомый еще по школе и в то же время нетривиальный,- метод решения квадратных уравнений вида ax2+bx+c=0. С его помощью можно решить например такую задачу об обезьянах:

"На две партии разбившись,
Забавлялись обезьяны.
Часть восьмая их в квадрате
В роще весело резвилась;
Криком радостным двенадцать
Воздух свежий оглашали.
Вместе сколько ты мне скажешь
Обезьян там было в роще?"

Задача взята из трактата знаменитого индийского математика и астронома Бхаскары II (1114-1185 гг.) "Сиддханта-широмани" ("Венец учения"). Перевел ее на русский и опубликовал в своей книге "Кто изобрел алгебру?" московский профессор Василий Иванович Лебедев (1883-1952 гг.).

Условие задачи легко переводится на язык современных алгебраических обозначений. Обозначим число всех обезьян через x. Тогда

или

x2 - 64x + 768 = 0.

Уравнение имеет два решения: x1=48 и x2=16. Оба они подходят под смысл задачи.

Даже если мы запишем это уравнение на подходящем языке программирования и введем в компьютер, он не сможет сам найти решение: мыслить машина не умеет. Программировать нужно решение или способ поиска решения, найденные человеком - разумным существом. Скажем, шахматная программа сама находит лучшие ходы, перебирая множество вариантов и оценивая их по неким критериям. Но и процедура перебора и критерии оценки задаются программистом.

Каждый школьник знает "волшебные" формулы для корней квадратного уравнения:


и

На их базе действительно можно разработать работающую программу, но сами по себе они еще не алгоритм решения. Дополнительно нужно точно определить:

После этого останется записать алгоритм на языке, понятном компьютеру.

Начнем с исключительных случаев. Они не всегда очевидны, для их определения нужны знание математики и опыт.

Допустим, что во входных данных a=0. Тогда наши школьные формулы не сработают, компьютер выдаст ошибку из-за деления на ноль. Если обратиться к исходному уравнению, станет ясно, почему так получилось: уравнение вместо квадратного стало линейным. Теперь нужно принять решение, что делать в этом случае, так как компьютер сам сделать этого не сможет. Тут возможны варианты. Это может быть ошибка во входных данных. Тогда выполнение условия a=0 может стать сигналом к прекращению работы программы. Или же алгоритм будет предусматривать и решение линейного уравнения в этом частном случае. Остановимся на втором варианте: вычислим один корень и будем дополнительно выводить на печать число корней. Если уравнение квадратное, напечатаем число корней 2, если линейное - 1.

Другой исключительный случай связан с тем, что при b2-4ac<0 у нас будут появляться комплексные корни, содержащие мнимую единицу i (i2=-1). Формулы написаны так, что их можно применять как в случае действительных, так и комплексных корней, но ход вычислений для этих двух случаев будет сильно отличаться. Действительно, для двух комплексных корней нужно рассчитать четыре числа, для двух действительных - два. То есть в каждом случае должен быть свой алгоритм расчета. Но прежде нужно решить: является ли появление комплексных корней нормальным явлением или это сигнал об ошибке во входных данных. Это зависит от смысла поставленной задачи.

В целом понятно, что в алгоритме должна присутствовать проверка знака дискриминанта b2-4ac. Далее предположим, что комплексные корни допустимы и составим отдельные алгоритмы для нахождения комплексных и действительных корней. Для расчета удобно, что комплексные корни всегда появляются парами: их действительные части равны, а мнимые части отличаются друг от друга только знаком. При этом нельзя забывать, что арифметические операции могут проводиться лишь над действительными числами, поэтому при нахождении комплексного корня квадратный корень извлекается из числа, противоположного по знаку отрицательному дискриминанту.

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

Раньше блок-схемы использовались довольно часто. Они позволяли сделать наглядным процесс вычислений, в котором встречается выбор из нескольких вариантов и переходы от одной части программы к другой. Особенно это было актуально для самых первых компьютерных языков, близких к машинному коду. Однако эволюция языков программирования привела к тому, что современные программы легко читаются человеком и нужды в дополнительных пояснениях к коду вроде блок-схем больше нет, достаточно простых текстовых комментариев. Тем не менее в учебных целях блок-схемы иногда еще используют.

Основной элемент любой блок-схемы - это прямоугольник, обозначающий вычислительные операции любого вида. Там, где в алгоритме проводится проверка или сравнение, ставят ромб с записанным внутри условием. Ни одна программа не обходится без ввода и вывода данных (параллелограмм), а также запуска и останова (овал).

Получившаяся в результате блок-схема приведена ниже (рис.1.1).

Рис.1.1. Блок-схема алгоритма нахождения корней квадратного уравнения

Примеры работающих программ, написанных в соответствии с этим алгоритмом, будут приведены позднее.

Простейшая механическая модель числа и операций над числами: машина Поста

Уже говорилось, что компьютер - это устройство для механического моделирования числа и операций над числами. Лучше всего иллюстрирует это утверждение так называемая абстрактная вычислительная машина Поста. "Абстрактная" означает, что это не реальная конструкция, а скорее мысленный эксперимент (хотя в принципе ее можно изготовить "в металле"). Ее предложил американский математик Эмиль Пост в 1936 г. Схожую идею независимо и чуть раньше выдвинул британский математик Алан Тьюринг (абстрактная вычислительная машина Тьюринга). Машина Поста проще, поэтому рассмотрим именно ее.

Что нужно, для того чтобы смоделировать число? Любой набор одинаковых предметов вполне передает идею числа: задачки про яблоки и конфеты здорово помогают нашим детям учиться счету. Робинзон Крузо моделировал число, делая зарубки на дереве:

"Вскоре после того, как я поселился на острове, мне вдруг пришло в голову, что я потеряю счет времени и даже перестану отличать воскресенья от будней, если не заведу календаря.

Календарь я устроил так: обтесал топором большое бревно и вбил его в песок на берегу, на том самом месте, куда меня выбросило бурей, и прибил к этому столбу перекладину, на которой вырезал крупными буквами такие слова:

ЗДЕСЬ Я ВПЕРВЫЕ СТУПИЛ НА ЭТОТ ОСТРОВ 30 СЕНТЯБРЯ 1659 ГОДА

С тех пор я каждый день делал на своем столбе зарубку в виде короткой черточки. Через шесть черточек я делал одну длиннее - это означало воскресенье; зарубки же, обозначающие первое число каждого месяца, я делал еще длиннее. Таким образом я вел мой календарь, отмечая дни, недели, месяцы и годы" (Д.Дефо. Робинзон Крузо).

Если бы у Робинзона была бумага, он мог бы делать на ней пометки - результат был бы тем же.

В машине Поста специальное устройство - каретка со считывающей и записывающей головкой - ставит или стирает метки на длинной ленте, разделенной для удобства на ячейки. Почти как школьник, рисующий в своей прописи ряды одинаковых палочек карандашом и всегда имеющий возможность их стереть с помощью стерки.

Сколько команд нужно для реализации такого устройства? Две - для перемещения каретки вдоль ленты, две - для нанесения и удаления меток, команда условного выбора и стоп. Всего шесть:

Обозначение
Действие
Каретка смещается на одну ячейку вправо
Каретка смещается на одну ячейку влево
В ячейку, рядом с которой находится каретка, ставится метка
Каретка стирает метку в ближайшей ячейке
? b1,b2
Проверяется содержимое текущей ячейки:
если в ней нет метки - выполняется команда с номером b1,
если метка есть - команда с номером b2
!
Машина прекращает работу

Рассмотрим простейшую задачу - прибавление к произвольному натуральному числу единицы. Разработаем алгоритм ее решения на машине Поста и запишем его в виде программы, "понятной" этому устройству, т.е. только с помощью перечисленных выше команд.

Заданное число логично моделировать соответствующим количеством меток, проставленных подряд, без пропусков в ячейках ленты. Такую последовательность отмеченных ячеек будем называть массивом. Фактически, массив это и есть модель числа. Для определенности возьмем число 4. Пусть в исходном положении каретка находится рядом с одной из ячеек массива.

Рис.1.2. Лента, на которую нанесен массив, моделирующий число 4

Для того чтобы увеличить длину массива на единицу, достаточно справа (или слева) добавить к нему еще одну метку. Следовательно, нужно переместить каретку к первой свободной ячейке справа от массива и поставить там метку. План действий, то есть алгоритм решения задачи, готов. Мы получили его благодаря творческой работе мысли, хотя и очень простой. Теперь это готовое решение надо записать на языке команд машины Поста.

Номер команды Команда Комментарий
1
Ищем последнюю ячейку заданного массива: перемещаем каретку на одну ячейку вправо.
2
? 3,1
Если в ячейке, рядом с которой остановилась каретка, метки нет, значит достигнут конец массива и в этой ячейке нужно поставить метку, увеличив первоначальное число на единицу (команда с номером 3). Если же метка присутствует, поиск конца массива нужно продолжать, возвращаясь к команде номер 1.
3
В первую пустую ячейку справа от массива ставится метка. Заданное натуральное число увеличилось на единицу.
4
!
Конец программы.

Проверьте, как машина Поста выполнит эту программу, мысленно или с помощью листа бумаги в клеточку. В принципе, в Сети есть эмуляторы машины Поста для Windows (утилита для открытия файлов справки .hlp), но на мой взгляд абстрактная машина должна оставаться абстрактной. Это инструмент не для программистов, а для математиков, которые доказывают теоремы, связанные с алгоритмами.

Что общего у примитивной и скучной абстрактной вычислительной машины и у компьютера на вашем столе? Фокус в том, что их возможности одни и те же, просто современные компьютеры сложны, быстры и удобны. На самом деле ваш любимый ноутбук не делает ничего, что не могла бы сделать машина Поста. Согласно известному тезису Чёрча-Тьюринга, любая функция, которая может быть вычислена физическим устройством, может быть вычислена машиной Тьюринга (или машиной Поста, они эквивалентны). Фактически, машину Поста можно считать формальным определением алгоритма.

Благодаря своей простоте, вычислительная машина Поста очень полезна для иллюстрации того, что такое компьютер и программирование.

Литература

  1. Успенский В.А. Машина Поста.- М.: Наука, 1988.- 96 с.

Архитектура фон Неймана. Машинные коды

Программирование - в высшей степени практическая, прикладная дисциплина. Попытка прояснить какой-либо его вопрос неизбежно ведет к столкновению с большим количеством новой технической информации. Это так, потому что современные компьютеры состоят из колоссального числа элементов, сложным образом взаимодействующих друг с другом. Примитивный принцип действия компьютера, полностью описываемый машиной Поста, резко контрастирует со сложностью его устройства.

Таким образом, преподавание программирования - всегда вызов для педагога. Нужно уметь добиться ясности понимания, не погрязнув в трясине технических подробностей вместе со своими учениками. Большинство текстов, написанных профессиональными программистами, невозможно читать из-за обилия технических деталей. Они понятны только таким же "посвященным", как и их авторы. [Речь, разумеется, идет не о классиках - Кернигане, Ритчи, Плоджере, Пайке, Кнуте и других хороших авторах-программистах. Их книги прекрасны.]

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

Подавляющее большинство компьютеров, созданных в прошлом и существующих ныне, работают по схеме, которую принято называть архитектурой фон Неймана. Она основывается на следующих принципах:

Название Принцип Достоинства и недостатки
Однородность памяти
Команды и данные хранятся в одной и той же памяти и внешне неразличимы В альтернативной - т.н. гарвардской архитектуре - для программы и данных предполагается отдельная память. Но иметь два различных вида памяти - дорогое удовольствие. Хотя разделение памяти может дать некоторый прирост в быстродействии (за счет возможности одновременно считывать команды и оперировать с памятью данных) и дополнительно защитить программный код от вирусов.
Программное управление
Программа состоит из серии элементарных команд, которые обычно не содержат данных (указывается только их адрес), поэтому программа не зависит от обрабатываемых данных (своего рода прототип переменных в математике). Команды выполняются одна за другой, в том порядке, в котором они находятся в памяти. Для изменения порядка выполнения команд используются команды условного или безусловного перехода. Позволяет реализовать одновременное хранение в памяти и самих команд и данных.
Двоичное кодирование
Для представления команд и данных используется двоичная система счисления. Главное достоинство - простота реализации по сравнению с десятичной или троичной системами счисления. Хотя троичные вычислительные машины в определенных ситуациях работают быстрее.

Кажущаяся совершенно естественной из-за своей привычности, архитектура фон Неймана - это красивое инженерное решение. Она не оптимальна с точки зрения быстродействия, которым пришлось пожертвовать ради простоты реализации. Простота в инженерном деле почти всегда является плодом компромисса. Простые решения - дешевле и надежнее. Простота не всегда возможна, но к ней нужно стремиться.

Теперь разберем схему вычислительной машины, предложенную фон Нейманом (рис.1.3), более подробно.


Рис.1.3. Архитектура фон Неймана

В ней четко выделяются два взаимодействующих друг с другом больших блока: основная память и центральный процессор.

Память - это своего рода электронная записная книжка. Она делится на ячейки ("страницы") одинакового размера, порядковый номер ячейки считается ее адресом. В одну ячейку помещается 1 байт (8 бит - например, 10111100) информации. Записанную информацию можно стереть (при этом она исчезает навсегда) и записать вместо нее новую. Другими словами, память - аналог ленты машины Поста.

Центральный процессор производит обработку данных: имеются в виду простые арифметические и логические операции или доступ к заданному месту в памяти. В машине Поста этому соответствует взаимодействие каретки с определенной ячейкой на ленте. Аналогия разумеется неполная - в одной ячейке машины Поста может быть записан только 1 бит информации (1 или 0); не оговаривается, где записывается программа, управляющая действиями каретки; арифметические операции для машины Поста отнюдь не элементарны и т.д.и т.п.

Архитектура фон Неймана подразумевает вычислительную машину на базе электронных компонентов. Логично поэтому, что центральный процессор и память, будучи электронными устройствами, взаимодействуют через два набора проводов, которые принято называть адресной шиной и шиной данных. Кроме них есть еще один отдельный провод (на рисунке он не показан), по которому из центрального процессора в память передается один бит информации (1 или 0), сигнализирующий, будут данные считываться из памяти или записываться в нее. Этот провод называется шиной управления.

Физически процессор представляет собой кремниевую плату или "подложку" с логическими цепями, соcтоящими из транзисторов, скрытую в пластмассовом корпусе с контактными ножками-выводами. Большинство ножек процессора подключено к шинам, связывающим интегральную микросхему (чип) процессора с остальными частями компьютера. Остальные ножки служат для подачи питания на сам чип.

Один провод шины компьютера может передавать один бит. Значение этого бита (1 или 0) определяется уровнем напряжения в проводе. Значит, к примеру, процессор с одной 16-разрядной шиной и одной 8-разрядной должен иметь 24 (16 + 8) ножки, соединенные с различными проводами.

Управляет получением команд из памяти и их декодированием устройство управления - контроллер. Контроллер не обрабатывает команду: после декодирования он просто передает ее по внутренней шине управления к другим модулям процессора, которые выполняют необходимое действие.

Важно понимать, что в архитектуре фон Неймана именно центральный процессор определяет адрес ячейки памяти, с которой будет взаимодействовать, т.е. он генерирует и посылает информацию об адресе через адресную шину. Отослать адрес обратно процессору память не может: это движение в одном направлении.

Передав нужный адрес, процессор посредством шины управления определяет, что будет делаться с информацией, хранящейся по этому адресу. Есть два варианта: чтение и запись. При чтении копия содержимого ячейки памяти с заданным адресом передается по шине данных контроллеру. При записи происходит пересылка информации из процессора в память и сохранение ее в ячейке с заданным адресом. То есть движение информации по шине данных - двунаправленное.

Арифметико-логическое устройство - это часть процессора, которая выполняет арифметические (в простейшем случае - операции отрицания и сложения; другие арифметические действия - вычитание, умножение и целочисленное деление - могут быть сведены к ним) и логические (логическое сложение И, логическое умножение ИЛИ, исключительное ИЛИ) действия, а также способна сдвигать биты влево и вправо.

Процессор выполняет команды намного быстрее, чем читает их из памяти. Поэтому для экономии времени процессор снабжен временным хранилищем команд и данных - регистрами. Размер регистра - несколько байтов, зато доступ к регистрам осуществляется почти мгновенно. Регистры общего назначения содержат рабочие данные, полученные из памяти. В регистрах состояния хранится текущее состояние процессора. Так называемый счетчик содержит адрес следующей команды.

Итак, язык, "понятный" компьютеру, созданному на базе архитектуры фон Неймана, представляет собой последовательность нулей и единиц. Этот язык называется машинным кодом. Для лучшего понимания можно разобрать пример, позаимствованный из книги Üçoluk G., Kalkan S. "Introduction to Programming Concepts with Case Studies in Python":

Адрес в памяти Команда Комментарий
8700
10001010
Загрузить в РЕГИСТР1 целое число, которое записано в следующих ячейках памяти
8701
00011001
Целое число 6452, которое будет загружено в РЕГИСТР1. Оно записано в двоичной системе исчисления (здесь можно убедиться, что 11001001101002=645210)
8702
00110100
8703
10001011
Загрузить в РЕГИСТР2 другое целое число, которое записано в следующих ячейках памяти
8704
00000011
Целое число 1009, которое будет загружено в РЕГИСТР2. Оно записано в двоичной системе исчисления (здесь можно убедиться, что 11111100012=100910
8705
11110001
8706
00010011
Команда прибавить к содержимому РЕГИСТРА1 содержимое РЕГИСТРА2
8707
11000010
Команда сохранить содержимое РЕГИСТРА1 по адресу, который записан в следующих ячейках памяти
8708
00100010
Адрес 8713 ячейки памяти, в которую будет записано содержимое РЕГИСТРА1
8709
00001001
8710
00000001
Команда перейти к адресу, который записан в следующих ячейках памяти, чтобы найти там очередную команду
8711
00100010
Адрес 8715, куда должна перейти программа (100010000010112=871510)
8712
00001011
8713
После выполнения программы здесь будет сохранено число 7461 - результат сложения 6452 и 1009, перенесенное сюда из РЕГИСТРА1
8714

Легко себе представить, насколько трудно вручную писать программу в машинных кодах! Они идеально подходят к машине, но очень не удобны для человека. Поэтому для облегчения труда программиста вместо машинных кодов для программирования процессоров стали использовать так называемые языки ассемблера. Это своего рода промежуточное звено между обычными языками программирования (такими как C, Pascal, Python и т.д.) и машинными кодами. В ассемблере машинные команды записываются в символьной форме.

При этом язык ассемблера фактически остается отражением архитектуры процессора, и изучение языка в сущности означает изучение системы команд и способов адресации, реализуемых процессором. У каждой модели процессора - свой, а то и несколько, языков ассемблера. Поэтому, как и машинные коды, языки ассемблера относят к низкоуровневым языкам программирования. Интересно, хотя и вряд ли неожиданно, что самый первый на свете ассемблер пришлось писать вручную на машинных кодах.

Литература

  1. Üçoluk G., Kalkan S. Introduction to Programming Concepts with Case Studies in Python.- Springer-Verlag Wien, 2012.- 221 p.
  2. Марек Р. Ассемблер на примерах. Базовый курс.- СПб.: Наука и Техника, 2005.- 240 с.

Язык программирования низкого уровня: ассемблер программируемого калькулятора МК-61

Для иллюстрации эволюции языков программирования от машинных кодов до современных C и Python, годится любой язык ассемблера. Можно было бы взять язык гипотетического компьютера MIX/MMIX, придуманный Дональдом Кнутом для его знаменитой монографии "Искусство программирования", или ассемблер какого-нибудь реально существовавшего/существующего процессора. Но мы остановимся на более простом и близком для русскоязычного читателя варианте - советском программируемом микрокалькуляторе МК-61.

Для многих людей моего поколения и старших микрокалькулятор стал первым контактом с волшебным миром программирования. Первая любовь, как известно, самая крепкая. Теплые чувства к маленькому черному другу остались и по сей день.

Не последнюю роль в буме микрокалькуляторов в Советском Союзе сыграло то, что вокруг них сложилась определенная культура: был выпущен целый пласт литературы - журнальных статей и книг, включая научно-фантастические повести и компьютерные игры. Новая технология привлекла к себе лучшие интеллектуальные кадры страны, которых тогда в СССР хватало.

Эпоха микрокалькуляторов началась в середине 1980-х и закончилась в начале 1990-х с появлением первых персональных компьютеров, которые могли работать не только с числами, но и с символьной и графической информацией, а также поддерживали более простые языки программирования (например, Basic). Правда, новосибирская фирма НПП "СЕМИКО" разработала и с 2009 г. выпускает "Электронику МК-161" и другие современные модели калькуляторов, поддерживающие систему команд старых советских МК-52 и МК-61. На практике их можно использовать, например в качестве управляющего устройства для лабораторного оборудования, но в целом - это экзотика.

Использовать сегодня микрокалькуляторы для обучения программированию - плохая идея. Прежде всего из-за использования в них языка ассемблера. Он прост, потому что включает в себя всего несколько команд. И он сложен, потому что на нем трудно писать программы. Для наших иллюстративных целей ассемблер для МК-61 подходит как нельзя лучше, потому что его нетрудно обозреть весь целиком: процессор для любого, самого простого, персонального компьютера и соответственно его язык ассемблера - намного сложнее.

Ниже приводится таблица всех команд ассемблера МК-61. Как видно, всего их 214. В одну ячейку основной памяти (в МК-61 их было 105) может быть записано одно двузначное шестнадцатиричное число (код команды): ему соответствует либо какая-нибудь команда, либо цифра - часть числа, представляющего входные данные. Записывать числовую информацию в основную память калькулятора можно, но невыгодно, потому что на каждую цифру или знак десятичной запятой тратится по одной ячейке памяти. Поэтому входные данные как правило вводятся в так называемые регистры памяти (их в МК-61 было 15: RG0-RG9, RGa-RGe) или в регистры стековой памяти (X, Y, Z, T и особый регистр X1, куда записывается прежнее содержимое регистра X; вводимая с клавиатуры информация попадает в регистр X, именно его содержимое отображается на индикаторе калькулятора). Любой регистр может хранить одно десятичное дробное число.

Как пользоваться таблицей? Код команды состоит из двух символов: первый записывается в первом белом столбце таблицы, второй - в верхней белой строке. К примеру, код команды, вызывающей число π, - 20. Если навести курсор мыши на любую клетку таблицы, достаточно современный браузер покажет подсказку - краткое описание команды. Цветом выделены разные группы команд по назначению.

  2-й символ
0 1 2 3 4 5 6 7 8 9 - L C Г Е
0
0
1
2
3
4
5
6
7
8
9
,
/-/
ВП
Cx
B↑
FBx
1
+
-
×
÷
F10x
Fex
Flg
Fln
Fsin-1
Fcos-1
Ftg-1
Fsin
Fcos
Ftg
2
F√
Fx2
F1/x
Fxy
F⟲
K→°′
K→°′″
3
K←°′″
Kǀxǀ
KЗН
K←°′
K[x]
K{x}
Kmax
K∧
K∨
K⊕
KИНВ
KСЧ
4
x→П0
x→П1
x→П2
x→П3
x→П4
x→П5
x→П6
x→П7
x→П8
x→П9
x→ПA
x→ПB
x→ПC
x→ПD
x→ПE
5
С/П
БП
В/О
ПП
КНОП
Fx≠0
FL2
Fx≥0
FL3
FL1
Fx<0
FL0
Fx=0
6
П→x0
П→x1
П→x2
П→x3
П→x4
П→x5
П→x6
П→x7
П→x8
П→x9
П→xA
П→xB
П→xC
П→xD
П→xE
7
Kx≠0 0
Kx≠0 1
Kx≠0 2
Kx≠0 3
Kx≠0 4
Kx≠0 5
Kx≠0 6
Kx≠0 7
Kx≠0 8
Kx≠0 9
Kx≠0 A
Kx≠0 B
Kx≠0 C
Kx≠0 D
Kx≠0 E
8
KБП0
KБП1
KБП2
KБП3
KБП4
KБП5
KБП6
KБП7
KБП8
KБП9
KБПA
KБПB
KБПC
KБПD
KБПE
9
Kx≥0 0
Kx≥0 1
Kx≥0 2
Kx≥0 3
Kx≥0 4
Kx≥0 5
Kx≥0 6
Kx≥0 7
Kx≥0 8
Kx≥0 9
Kx≥0 A
Kx≥0 B
Kx≥0 C
Kx≥0 D
Kx≥0 E
-
KПП0
KПП1
KПП2
KПП3
KПП4
KПП5
KПП6
KПП7
KПП8
KПП9
KППA
KППB
KППC
KППD
KППE
L
Kx→П0
Kx→П1
Kx→П2
Kx→П3
Kx→П4
Kx→П5
Kx→П6
Kx→П7
Kx→П8
Kx→П9
Kx→ПA
Kx→ПB
Kx→ПC
Kx→ПD
Kx→ПE
C
Kx<0 0
Kx<0 1
Kx<0 2
Kx<0 3
Kx<0 4
Kx<0 5
Kx<0 6
Kx<0 7
Kx<0 8
Kx<0 9
Kx<0 A
Kx<0 B
Kx<0 C
Kx<0 D
Kx<0 E
Г
KП→x0
KП→x1
KП→x2
KП→x3
KП→x4
KП→x5
KП→x6
KП→x7
KП→x8
KП→x9
KП→xA
KП→xB
KП→xC
KП→xD
KП→xE
E
Kx=0 0
Kx=0 1
Kx=0 2
Kx=0 3
Kx=0 4
Kx=0 5
Kx=0 6
Kx=0 7
Kx=0 8
Kx=0 9
Kx=0 A
Kx=0 B
Kx=0 C
Kx=0 D
Kx=0 E

Рис.1.4. Эмулятор МК 61/54 для Android

Все команды языка МК-61 можно разделить на семь групп:

  1. Ввод числовой информации
    • цифры от 0 до 9 (коды от 00 до 09)
    • десятичная запятая (0-)
    • подготовка ввода порядка числа (0C)
    • обнуление регистра X или удаление введенного числа ()
  2. Арифметические операции
    • сложение + (код 10)
    • вычитание - (11)
    • умножение × (12)
    • деление ÷ (13)
    • смена знака числа /-/ (0L)
  3. Логические операции
    • логическое сложение ∨ (код 38)
    • логическое умножение ∧ (37)
    • логическая операция "Исключающее ИЛИ" ⊕ (39)
    • логическая операция "Инверсия" (3-)
  4. Вычислительные функции
    • извлечение квадратного корня √ (код 21)
    • возведение в квадрат x2 (22)
    • получение обратной величины 1/x (23)
    • возведение числа 10 в любую степень 10x (15)
    • возведение в степень числа e, основания натуральных логарифмов ex (16)
    • вычисление десятичного и натурального логарифмов lg (17) и ln (18)
    • вычисление тригонометрических функций sin (1C), cos (), tg (1E), а также обратных тригонометрических функций arcsin (19), arccos (1-) и arctg (1L)
    • возведение произвольного числа в любую степень xy (24)
    • определение модуля числа ǀxǀ (31)
    • определение знака числа (32)
    • выделение целой части числа [x] (34)
    • выделение дробной части числа {x} (35)
    • определение максимального из двух чисел (36)
    • генерация псевдослучайного числа от 0 до 1 (3L)
    • перевод угловых/временных величин, выраженных в градусах/часах, минутах и долях минуты, в значения, выраженные в градусах/часах и долях градуса/часа (26) и обратно (33)
    • перевод угловых/временных величин, выраженных в градусах/часах, минутах, секундах и долях секунды, в значения, выраженные в градусах/часах и долях градуса/часа (2-) и обратно (30)
  5. Считывание и запись информации в регистры данных
    • непосредственное и косвенное копирование содержимого регистра X в регистры данных RG0-RG9, RGa-RGe (коды c 40 по 4E и с L0 по LE)
    • вызов в регистр X содержимого регистра данных RG0-RG9, RGa-RGe (коды c 60 по 6E)
    • вызов в регистр X содержимого регистра, адрес которого записан в регистре RG0-RG9, RGa-RGe (коды c Г0 по ГE)
    • вызов в регистр X значения числа π, "зашитого" в постоянную память микрокалькулятора (код 20)
  6. Команды управления ходом вычислений
    • команда останова стоп/пуск для приостановки процесса вычислений, когда нужно либо прочесть полученный результат, либо ввести с клавиатуры какие-нибудь числа или команды, С/П (код 50)
    • ввод/останов В/О (код 52)
    • команды для организации циклов с помощью регистров RG0-RG3 (коды , 5L, 58, 5- соответственно)
    • команда безусловного перехода, передающая управление команде, адрес которой записан сразу после нее, БП (код 51) и команды косвенного безусловного перехода, передающие управление команде, адрес которой записан в регистре RG0-RG9, RGa-RGe (коды с 80 по 8E)
    • команды прямого условного перехода: x<0 (код 5C), x=0 (5E), x≠0 (57), x≥0 (59) и косвенного условного перехода: x<0 (коды с C0 по CE), x=0 (E0-EE), x≠0 (70-7E), x≥0 (90-9E)
    • команды прямого ПП (код 53) и косвенного перехода на подпрограмму (коды с -0 по -E)
    • пустая, ничего не делающая команда-заглушка К НОП (код 54)
  7. Команды, управляющие перемещением чисел по регистрам стека
    • разделение вводимых чисел и сдвиг чисел в стеке регистров снизу вверх B↑ (0E)
    • вызов содержимого регистра предыдущего результата в регистр X FBx (0)
    • обмен содержимым между регистрами X и Y ↔ (14)
    • передвижение информации в стеке регистров по кругу F⟲ (25)

Естественная реакция при первом знакомстве с языком МК-61 - удивление: как с помощью столь скудного набора команд при всех ограничениях микрокалькулятора на длину программы, число регистров и т.п. получается решать довольно сложные математические задачи? Вспомним, однако, машину Поста: с ее помощью в принципе можно проводить расчеты любой сложности, а язык состоит вообще всего из 6 команд. Другое дело, что простота языка неизбежно приводит к изощренному, почти не читаемому коду.

Посмотрим, к примеру, как на языке МК-61 реализуется алгоритм решения квадратных уравнений, описанный в разделе "Модели и алгоритмы". Приводимый здесь программный код принадлежит И.Д.Данилову. Он был опубликован в журнале "Техника молодежи" в 1985 г. При желании его можно запустить на эмуляторе МК-61 для Android.

Программа рассматривает следующие ситуации. Если в исходных данных a=b=0, то выпадает неизвестная величина x и корней у уравнения нет. Если a=0 и b≠0, уравнение из квадратного превращается в линейное с единственным корнем x=-c/b. Если a≠0 и b≠0 и дискриминант неотрицательный, то у квадратного уравнения будет два действительных корня: x1=(-B+d1/2)/a; x2=(-B-d1/2)/a. Здесь B=b/2; d=B2-ac. Если же a≠0 и b≠0 и под знаком квадратного корня оказывается отрицательное число, то корни уравнения получаются комплексными: x1=xr+ixim и x2=xr-ixim. Здесь i=(-1)1/2 - мнимая единица; xr=-B/a - действительная часть комплексного корня; xim=(-d)1/2/a - мнимая часть комплексного корня.

Адрес Команда Код Стек Комментарий
X Y Z T X1
00
x→ПA
4-
a
Запись переменной a в регистр A
01
С/П
50
b
a
Останов программы для ввода переменной b
02
B↑
0E
b
b
a
Подготовка стека для приема значения c
03
С/П
50
c
b
a
Ввод последнего коэффициента квадратного уравнения - переменной c. Команда С/П запускает программу
04
/-/
0L
-c
b
a
Вычисляем c1=-c
05
П→xA
6-
a
c1
b
Вызываем а из ее "собственного" регистра A
06
Fx=0
5E
Проверяем, равна ли нулю переменная а, находящаяся в регистре X
07
23
23
Если условие а=0 не выполняется, переходим к команде 23. Если же a=0, значит уравнение не квадратное, а первого порядка
08
F⟲
25
c1
b
a
Цель этой и последующей команды - вернуть в регистр X значение b
09
14
b
c1
10
Fx≠0
57
Если b=0, переходим к команде по адресу 19 (это ситуация, когда уравнение нулевого порядка и корней нет вообще), иначе - по адресу 12
11
19
19
12
÷
13
c1/b
Вычисляем единственный корень линейного уравнения (когда a=0)
13
П→x3
63
E01
x1
Вызываем в регистр X сообщение E01 из регистра 3, сигнализирующее, что у уравнения только один корень
14
С/П
50
Останавливаем программу, чтобы можно было прочесть сообщение E01
15
14
x1
E01
После нажатия клавиши С/П значение единственного корня выводится на индикатор
16
С/П
50
17
БП
51
Управление передается последней команде программы, все остальные ветви пропускаются и работа программы заканчивается
18
59
59
19
П→x0
60
E00
b
Сюда мы попадаем только в том случае, если a=b=0. Вычислений проводить не надо. Просто выводим на экран сообщение E00, означающее, что корней нет, и уходим на конец программы
20
С/П
50
21
БП
51
22
59
59
23
×
12
ac1
b
a
Если мы попали на эту команду, значит уравнение невырожденное и надо вычислять дискриминант и находить два корня
24
14
b
ac1
a
Переводим в регистр X переменную b и начинаем вычислять дискриминант d2
25
2
02
2
b
ac1
a
Вводим в регистр X число 2
26
÷
13
b/2=B
ac1
a
Делим коэффициент b на 2
27
x→ПB
4L
B
ac1
a
Результат деления B=b/2 запоминаем в регистре B
28
Fx2
22
B2
ac1
a
Величина B возводится в квадрат
29
+
10
B2+ac1
a
Вычисляется дискриминант d
30
П→xB
6L
B
d
a
Начинаем вычислять xr: вызываем величину B из регистра B в регистр X
31
П→xA
6-
a
B
d
Вызываем переменную a из регистра A
32
÷
13
B/a
d
a
Делим B на а
33
/-/
0L
xr
d
a
Меняем знак, получаем xr - действительную часть комплексных корней
34
x→П1
41
xr
d
a
Сохраняем xr в регистре 1
35
14
d
xr
Вызываем в регистр X величину d для анализа
36
Fx<0
5C
Если d≥0, то корни действительные и делается переход по адресу 48. Если же d<0, то корни комплексные и расчет проводится, начиная с команды 38
37
48
48
38
/-/
0L
-d
xr
a
Так как величина d отрицательна, то, перед тем как начинать вычислять корни, нужно поменять ее знак
39
F√
21
(-d)1/2
xr
a
Вычисляем квадратный корень из -d
40
П→xA
6-
a
(-d)1/2
xr
Для вычисления xim нужна переменная a, которую можно вызвать из регистра A
41
÷
13
(-d)1/2/a
xr
Величина xim=(-d)1/2/a вычислена и находится в регистре Х
42
П→x5
65
Г.
xim
xr
Все расчеты выполнены. Осталось вывести в регистр X из регистра 5 сообщение Г., сигнализирующее, что корни уравнения комплексные
43
С/П
50
Останов программы, чтобы пользователь мог прочитать сообщение
44
F⟲
25
xim
xr
После того как пользователь прочитал сообщение, возвращаем результаты вычислений на старое место и еще раз останавливаем программу, чтобы считать их
45
С/П
50
46
БП
51
Переход на конец программы
47
59
59
48
F√
21
d1/2
xr
a
Эта команда выполняется после команды по адресу 36, если d≥0 и у уравнения два действительных корня. На шаге 36 в регистре X находилась величина d, поэтому извлекаем квадратный корень
49
П→xA
6-
a
d1/2
xr
Вычисляем вспомогательное выражение d1/2/a
50
÷
13
d1/2/a
xr
51
+
10
xr+d1/2/a
Определяем первый корень x1
52
П→x1
61
xr
x1
d1/2/a
Вызываем xr из регистра 1. Величина d1/2/a переходит в регистр предыдущего результата X1
53
FBx
0
d1/2/a
xr
x1
В регистр X вызывается величина d1/2/a из регистра предыдущего результата X1
54
-
11
xr-d1/2/a
x1
Вычисляем второй корень x2. Расчет закончен
55
П→x4
64
E02
x2
x1
Из регистра 4 в регистр X пересылается сообщение E02, сигнализирующее, что у заданного уравнения два действительных корня
56
С/П
50
Останов программы, чтобы пользователь мог прочитать сообщение
57
F⟲
25
x2
x1
После того как пользователь прочитал сообщение, возвращаем результаты вычислений на старое место и еще раз останавливаем программу, чтобы считать их
58
С/П
50
59
БП
51
Работа программы завершена. Она возвращается к адресу 00
60
00
00

Инструкция по пользованию программой:

  1. В режиме программирования (F ПРГ) ввести программу в память калькулятора (эмулятора).
  2. Установить режим вычислений (F АВТ).
  3. Ввести обозначения-шифры для сообщений о числе корней:
    100  ВП  99  ВП  B↑  x→П0
    101  ВП  99  ВП  B↑  x→П3
    102  ВП  99  ВП  B↑  x→П4
    Cx  B↑  ÷  ВП  ВП  B↑  x→П5
  4. Очистить программный указатель (В/О).
  5. Ввести исходные данные: a С/П; b С/П; c С/П.
  6. Вывод: после первого останова на индикаторе появляется сообщение: E00 - корней нет; E01 - уравнение линейное, корень только один; E02 - два действительных корня; Г. - корни комплексные.
  7. Если корней нет, то для продолжения расчетов вернуться к п.5. Если корни есть, нажать С/П. После останова на индикаторе - значение первого корня (если корни действительные) или мнимой части комплексных. Для чтения другого корня или действительной части нажать ↔.
  8. Для продолжения расчетов перейти к п.5.

Надо признать, что это хорошо составленная программа, удобная и остроумная. Пояснения к коду тоже написаны хорошо. Но в конце 80-х годов автору этих строк, тогда старшекласснику без выдающихся способностей, разобраться в ней оказалось не под силу. При этом никаких проблем с решением квадратных уравнений вручную не было - тот случай, когда использование инструмента сложнее самой решаемой задачи. Мысль о том, что источник затруднений кроется в "низкоуровневости" языка МК-61, в то время в голову не приходила, потому что никаких персональных компьютеров с языками высокого уровня в СССР еще не было.

По сравнению с микрокалькулятором языки ассемблера для больших машин сложнее, а код читается легче благодаря возможности использовать символьно-буквенные обозначения для переменных и команд. Язык МК-61 вообще ближе к машинным кодам.

Здесь не ставится цели научить читателя считать на микрокалькуляторе или, чего доброго, программировать на нем. Приведенный пример носит иллюстративный характер. Писать программы и проводить быстрые расчеты а-ля калькулятор нужно на Python, а использовать эмулятор МК-61 как обычный калькулятор на платформе Android можно, если вам привычна польская (бесскобочная) система записи вычислений. Тогда это почти идеальный вариант - ничего лучше на Android нет. Вообще, предлагать человеку учить больше одного языка программирования - это изъян нашей системы образования. Такую "разносторонность" следует оставить тем, кто зарабатывает программированием себе на жизнь.

Советские программируемые микрокалькуляторы в свое время сыграли большую роль в преподавании программирования. Сейчас их использование стало бессмысленным не столько из-за технических ограничений, сколько из-за использовавшегося в них языка ассемблера. Тем не менее в старых книгах по микрокалькуляторам осталось немало ценного: программный код, конечно устарел, но многие задачи, идеи и алгоритмы вполне актуальны для обучения программированию на Python.

Литература

  1. Данилов И.Д. Язык микрокалькулятора // Техника молодежи.- 1985.- №4.- С.50-52.
  2. Программирование на калькуляторе.- 2011 г.

Эволюция языков программирования

То, что вообще может быть сказано, может быть сказано ясно,
а о чем невозможно говорить - о том следует молчать.
(Людвиг Витгенштейн. Логико-философский трактат)

Главной проблемой всех языков ассемблера была и остается их ориентированность на компьютер - механическую модель числа, а не на человека - автора идей и алгоритмов. Поэтому довольно скоро после начала распространения электронно-вычислительных машин стали появляться языки программирования другого типа, позволяющие программисту сосредоточиться на математическом содержании решаемой задачи, а не на программировании каждого отдельного регистра памяти. Эти новые языки стали называть языками высокого уровня в отличие от машинных кодов и языков ассемблера - языков низкого уровня.

Одним из первых языков высокого уровня, сыгравшим большую роль в эволюции последующих языков программирования, был ALGOL - ALGOrithmic Language (алгоритмический язык). Он был разработан в 1957-1960 гг. международной группой ученых и программистов как язык для записи алгоритмов. То есть, он уже не был привязан к внутреннему устройству компьютера, а ориентировался на удобство записи алгоритма решаемой задачи. Важно отметить, что алгоритм, записанный на языке ALGOL (и любом другом языке высокого уровня), не может быть непосредственно выполнен на компьютере; программа на ALGOL должна быть предварительно переведена на язык машины. К счастью, этот перевод может быть сделан автоматически самим компьютером при помощи специальной программы, написанной на ассемблере или в машинных кодах и называемой транслятором.

Итак, что же нужно сделать, чтобы программу на ALGOL выполнить на вычислительной машине? Вначале на языке ALGOL пишется исходная программа, представляющая собой алгоритм решения задачи, записанный в виде последовательности операторов ALGOL. Программа, не включающая исходные данные, переводится транслятором в рабочую программу, состоящую из элементарных команд (машинных кодов) того компьютера, на котором будет решаться задача. Во время этого перевода (трансляции) рабочая программа не выполняется, начальные данные не вводятся, результаты не выводятся. Затем, когда программа выражена в терминах, "понятных" машине, она выполняется: вводятся начальные данные, выполняются вычисления и выводятся результаты. Транслятор, который сам по себе представляет собой программу, во время исполнения рабочей программы не используется. Таким образом, слово "ALGOL" (как и слова "Fortran", "Pascal") включает в себя два смысла: 1) правила записи алгоритмов, т.е. собственно язык программирования; и 2) транслятор, переводящий запись алгоритма на ALGOL в машинные коды, "понятные" компьютеру.

Рассмотрим подробнее, что изменилось в языках высокого уровня по сравнению с языками ассемблера, сравнив язык МК-61 и ALGOL.

Группы команд Элементы языка Пример на МК-61 Пример на ALGOL Комментарий
Ввод буквенно-числовой информации Цифры 0 1 2 3 4 5 6 7 8 9 , - 0 1 2 3 4 5 6 7 8 9 . - Без изменений. В обоих случаях можно использовать порядок числа.
Буквы
-
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Буквы в языке МК-61 не применялись, но в языках ассемблера для больших машин они присутствуют.
Переменные
Регистры RG0-RG9, RGa-RGe
a34kTMNs
Имена переменных комбинируются из букв, цифр и других символов, присутствующих на клавиатуре. В роли переменных в МК-61 выступали регистры памяти, в языках ассемблера для компьютеров можно использовать обычные буквенно-цифровые имена переменных.
Строки
-
'.. This - is - а - 'string''
В языке МК-61 строк нет, в других ассемблерах они есть.
Типы переменных
-
integer, real, Boolean
Числа и переменные в ALGOL могут быть трех типов: integer (целые), real (действительные) и Boolean (логические)
Арифметические операции
+ - × ÷
2 B↑ 2 ×
a:=2*2;
Без изменений. Особенность ассемблера МК-61 - польская система записи вычислений.
Логические операции
∨ ∧ ⊕ ¬ и др.
237 ∧ 545
4 2 3 7 B↑
4 5 4 5 К ∧
a:=b∧c;
В ALGOL появляются дополнительные логические операции: ≡ (эквивалентно) и ⊃ (влечет). На языке МК-61 логические операции проводятся не над переменными, а только над числами, причем поразрядно.
Вычислительные функции
√, ex, sin и т.п.
2 F √
a:=sqrt(2);
Без изменений. Разумеется, вычислительные возможности ALGOL намного шире.
Считывание и запись информации в регистры данных
x→ПA
a:=x;
Программист на ALGOL не работает с памятью непосредственно. Она спрятана от него за чисто математическим понятием переменной. Правда, ему нужно самому явно задавать тип переменной; в обычной математической записи этого делать не нужно.
Команды управления ходом вычислений
Операторы условия, цикла, безусловного перехода; подпрограммы
F x=0 23
if x=0 then go to delta;
Программист на ALGOL не работает с памятью непосредственно. Она спрятана от него за чисто математическим понятием переменной. Правда, ему нужно самому явно задавать тип переменной; в обычной математической записи этого делать не нужно.
Команды, управляющие перемещением чисел по регистрам стека
B↑, X FBx, ↔, F⟲
2 B↑ 2 ×
-
В ALGOL команды такого рода отсутствуют.

И снова первая реакция - удивление. Оказывается, переход на высокий уровень отнюдь не означает усложнения языка программирования, появления каких-то принципиально новых групп команд и т.п. Наоборот, групп команд стало меньше. Выпали команды, непосредственно работающие с ячейками памяти. С другой стороны, "генетика" языка МК-61 и ALGOL определенно одна и та же. Вполне можно проследить, откуда взялась та или иная команда или концепция в языке высокого уровня. Все они уже были в языке ассемблера! И точно так же все они уже были в машинных кодах. Вывод: само программирование компьютера как механической модели числа при развитии языков программирования не меняется. Эволюция идет в направлении облегчения работы программиста. Решая задачу, ему уже не нужно думать о внутреннем устройстве процессора и памяти компьютера. Современные языки программирования "прячут" от него все технические детали, давая возможность думать о задаче как о чисто математической. Запись алгоритма на языке высокого уровня почти так же удобна, как и обычная математическая запись. Ограничение накладывается лишь наличием клавиатуры, из-за чего приходится обходиться набором символов ASCII.

Теперь обратимся к уже знакомой иллюстрации - реализации алгоритма решения квадратных уравнений, описанного в разделе "Модели и алгоритмы", но уже на ALGOL:

begin
   real a,b,c,x1real,x2real,x1imag,x2imag,disc,sqroot;
   integer roots;
   a:=1;
   b:=-2;
   c:=1;
   if a=0 then
      begin
      roots:=1;
      x1real:=-c/b;
      x2real:=0;
      go to zeros
      end;
   roots:=2;
   disc:=b**2-4*a*c;
   if disc<0 then
      begin
      x1real:=x2real:=-b/(2*a);
      x1imag:=sqrt(-disc)/(2*a);
      x2imag:=-x1imag;
      go to output
      end;
   sqroot:=sqrt(disc);
   x1real:=(-b+sqroot)/(2*a);
   x2real:=(-b-sqroot)/(2*a);
zeros:   x1imag:=x2imag:=0;
output:   print(`A     B   C   X1REAL X1IMAG X2REAL X2IMAG ROOTS');
   print(a,b,c,` ',x1real,`  ',x1imag,`  ',x2real,`  ',x2imag,`  ',roots);
end

Запустить этот код можно на интерпретаторе ALGOL algol60i (интерпретатор, а не компилятор, потому что этот вариант ALGOL реализован на Python). Для этого наберите в командной строке:

python algol60 file.a60

Что мы видим? Программа на ALGOL вдвое короче: она занимает 29 строк вместо 60 команд языка МК-61. Четкая структура программы, интуитивно понятные имена переменных делают код вполне читаемым без всяких блок-схем. Программисту не нужно держать в голове или записывать на бумаге состояние регистров памяти. Ясно, что составить программу на ALGOL и быстрее и легче, чем на языке ассемблера.

Проверить работу программы можно по набору тестовых данных, который, как и сам код примера, позаимствован (с минимальными изменениями) из книги Мак-Кракена "Программирование на АЛГОЛе".

Коэффициенты уравнения Ax2+Bx+C=0
Первый действительный корень или действительная часть первого комплексного корня X1REAL Мнимая часть первого комплексного корня X1IMAG Второй действительный корень или действительная часть второго комплексного корня X2REAL Мнимая часть второго комплексного корня X2IMAG Число корней ROOTS
A
B
C
1.0
-2.0
1.0
1.0
0.0
1.0
0.0
2
1.0
-7.0
10.0
5.0
0.0
2.0
0.0
2
6.0
-9.0
-6.0
2.0
0.0
-0.5
0.0
2
1.0
0.0
-1.0
1.0
0.0
-1.0
0.0
2
1.0
0.0
1.0
0.0
1.0
0.0
-1.0
2
1.0
-2.0
2.0
1.0
1.0
1.0
-1.0
2
4.0
24.0
20.0
-1.0
0.0
-5.0
0.0
2
100.0
200.0
100.0
-1.0
0.0
-1.0
0.0
2
0.0
63.9
-221.3
3.463
0.0
0.0
0.0
1
1.0
-4.0
8.739
2.0
2.176
2.0
-2.176
2
4.129
-14.811
-61.002
6.035
0.0
-2.448
0.0
2
-1.016
0.499
-49.573
0.245
-6.980
0.245
6.980
2
0.0
568.981
-490.652
0.862
0.0
0.0
0.0
1

Сегодня ALGOL - это мертвый язык в отличие от своего современника Фортрана. Но значение его - не в практическом применении. Он стал универсальным языком описания алгоритмов в научных публикациях. В Советском Союзе было выпущено значительное количество переводной литературы с алгоритмами на ALGOL (см. список литературы к этому разделу). И если переводить код, написанный для МК-61, скажем на Python, бессмысленно (проще написать новый с нуля), то алгоритм на ALGOL можно рассматривать как своего рода псевдокод, замену блок-схемам.

Литература

  1. Мак-Кракен Д.Д. Программирование на АЛГОЛе.- М.: Мир, 1964.- 184 с.
  2. Алгоритмический язык АЛГОЛ-60. Пересмотренное сообщение.- М.: Мир, 1965.- 79 с.
  3. Агеев М.И., Алик В.П., Галис Р.М., Марков Ю.И. Библиотека алгоритмов 1б-50б.- М.: Советское радио, 1975.- 176 с.
  4. Агеев М.И., Алик В.П., Марков Ю.И. Библиотека алгоритмов 51б-100б.- М.: Советское радио, 1976.- 136 с.
  5. Агеев М.И., Алик В.П., Марков Ю.И. Библиотека алгоритмов 101б-150б.- М.: Советское радио, 1978.- 128 с.
  6. Агеев М.И., Алик В.П., Марков Ю.И. Библиотека алгоритмов 151б-200б.- М.: Радио и связь, 1981.- 184 с.
  7. Агеев М.И., Марков Ю.И., Швакова Г.М. Алгоритмы (201-250).- М.: Институт проблем управления.- ВЦ АН СССР, 1971.- 210 с.
  8. Уилкинсон, Райнш. Справочник алгоритмов на языке АЛГОЛ. Линейная алгебра.- М.: Машиностроение, 1976.- 390 с.

Элементы языка Python

Python - это кратчайший путь от идеи до работающей программы
(Филипе Бионди)
Жизнь коротка, тебе нужен Python
(Брюс Экель)

Обзор базовых элементов Python в этом разделе фактически представляет собой перевод довольно удачного на мой взгляд мини-руководства по Python Филипе Лагадека.

Переменные

Переменные - это просто имена, указывающие на какое-либо значение или объект:

a_string = "hello, world"
an_integer = 12
a_float = 3.14
a_boolean = True

Печать

Так можно вывести на печать константу или переменную:

print "hello, world"
print 12
print (5+3)/2

Чтобы напечатать несколько элементов, воспользуйтесь запятыми (элементы будут отделены друг от друга пробелами):

print "abc", 12, a_float

Длинное выражение может быть разбито на части с помощью обратной косой черты:

print 'a long statement may be split using backslash', \
    'this is still the same statement', \
    'the end.'

Строки

Существует 3 варианта синтаксиса для строковых констант:

string_single_quotes = 'abc'
string_double_quotes = "abc"
string_triple_quotes = """this is  a multiline  string."""

Это может пригодиться, когда в состав строки входит символ кавычек:

string1 = 'hello "world"'
string2 = "don't"

иначе придется использовать обратную косую черту:

string2 = 'don\'t'

Другие специальные символы: https://docs.python.org/2.5/ref/strings.html

Строки - это объекты, поддерживающие множество операций:

strings = string1 + " : " + string2
strings_uppercase = strings.upper()

Все методы строк: https://docs.python.org/2.5/lib/string-methods.html

Срезы (выделение подстроки):

beginning = strings[0:4]

Больше о срезах:

Способы включить целое число в строку:

string1 = 'the value is ' + str(an_integer) + '.' # путем объединения

string2 = 'the value is %d.' % an_integer # путем "printf-подобного" форматирования

Если переменных несколько, придется использовать скобки:

a = 17
b = 3
string3 = '%d + %d = %d' % (a, b, a+b)

Чтобы включить строки в другую строку:

stringa = '17'
stringb = '3'
stringc = 'a = '+stringa+', b = '+stringb
stringd = 'a = %s, b= %s' % (stringa, stringb)

Все о форматировании строк: https://docs.python.org/2/library/stdtypes.html#string-formatting-operations

Преобразование строки в целое число и обратно:

i = 12
s = str(i)
s = '17'
i = int(s)

Удаление пробелов в начале и в конце строки:

stripped = a_string.strip()

Удаление подстроки из строки:

newstring = a_string.replace('abc', 'def')
Важное замечание:

строка в Python относятся к т.н. "неизменяемым" данным. Другими словами, это константа, изменить которую нельзя. Все операции над строками приводят к созданию новой строки. Это необычно для разработчиков на C, но неизбежно из-за некоторых свойств языка. В большинстве случаев это не вызывает никаких проблем.

Комментарии

Всегда полезно добавлять комментарии в ваши программы:

# Комментарии начинаются с "#"

Списки

Список - это динамический массив любых объектов.
Задается он с помощью квадратных скобок:

a_list = [1, 2, 3, 'abc', 'def']

Список может включать другие списки:

another_list = [a_list, 'abc', a_list, [1, 2, 3]]

(в данном случае "a_list" - лишь указатель)

Доступ к определенному элементу по порядковому номеру (нумерация начинается с нуля):

elem = a_list[2]
elem2 = another_list[3][1]

Так легко можно проверить, есть ли элемент в списке:

if 'abc' in a_list:
    print 'bingo!'

Выдление части списка называется срезом:

list2 = a_list[2:4] # возвращает список, состоящий из элементов 2 и 3 (но не 4)

Другие операции со списками, такие как добавление новых элементов:

a_list.append('ghi')
a_list.remove('abc')

Другие операции со списками: https://docs.python.org/2.5/lib/typesseq.html

Кортежи

Кортеж похож на список, но это неизменяемый массив фиксированной длины. Это значит, что после того как кортеж был создан, его элементы не могут быть изменены, удалены, добавлены или вставлены.

Он определяется с помощью круглых скобок и значений, отделенных друг от друга запятыми:

a_tuple = (1, 2, 3, 'abc', 'def')

Но скобки не обязательны:

another_tuple = 1, 2, 3, 'abc', 'def'

Подсказка: определение кортежа, состоящего только из одного элемента, обязательно должно содержать запятую, иначе он не будет кортежом:

a_single_item_tuple = ('one value',) 

Чуть больше о кортежах: http://docs.python.org/2/library/stdtypes.html#sequence-types-str-unicode-...

Блоки и отступы (управление ходом вычислений)

Блоки кода формируются с помощью отступов, то есть либо нескольких пробелов либо табуляции в начале строк. Это одно из главных отличий Python от прочих языков, и это главное, за что люди его любят или ненавидят. ;-)

Подсказка: НИКОГДА не используйте в своем коде символы табуляции и пробелы одновременно, это может привести к трудно идентифицируемым ошибкам.
Из моего опыта самым безопасным решением будет: всегда применять отступы из 4 пробелов, никогда не пользоваться табуляцией. (Потому что каждый редактор может конвертировать символы табуляции как в 2, так и в 4, и в 8 пробелов.)

IF / ELIF / ELSE:

if a == 3:
    print 'The value of a is:'
    print 'a=3'
 
if a == 'test':
    print 'The value of a is:'
    print 'a="test"'
    test_mode = True
else:
    print 'a!="test"'
    test_mode = False
    do_something_else()
 
if a == 1 or a == 2:
    pass # ничего не делать
elif a == 3 and b > 1:
    pass
elif a==3 and not b>1:
    pass
else:
    pass

Циклы WHILE:

a=1
while a<10:
    print a
    a += 1

Циклы FOR:

for a in range(10):
    print a
 
my_list = [2, 4, 8, 16, 32]
for a in my_list:
    print a

Дополнительно о ключевых словах, относящихся к управлению ходом вычислений: https://docs.python.org/2/tutorial/controlflow.html

Функции

Функция определяется с помощью ключевого слова "def":

def my_function (arg1, arg2, arg3='default value'):
    print 'arg1 =', arg1
    print 'arg2 =', arg2
    print 'arg3 =', arg3

Как ее вызывать (заметьте, что аргументы не сильно типизированные):

my_function (17, 'abc', 3.14)

[Вообще, Python - это сильно типизированный язык. Поясним последний термин. В слабо типизированных языках компилятор/интерпретатор будет иногда менять тип переменной. Например, в некоторых языках (таких как JavaScript) можно складывать строки с числами: 'x' + 3 будет 'x3'. Это может приводить к проблемам, потому что, если вы сделаете в своей программе ошибку, то вместо того, чтобы вывести сообщение об исключении, выполнение программы продолжится, а ваши переменные будут иметь неверные и неожиданные значения. В сильно типизированном языке (как Python) совершать операции, не соответствующие типу объекта, нельзя - складывать числа со строками не получится. Такие проблемы легче диагностировать, поскольку сообщение об исключении появится именно там, где возникает ошибка, а не в каком-то другом потенциально далеком месте. (Why is Python a dynamic language and also a strongly typed language)]

Третий аргумент может быть опущен:

my_function ('a string', 12)

Функция может возвращать значение:

def fun2():
    print 'fun2'
    return 'any return value'

ее вызов:

print 'fun2() = %s' % fun2()

Аргументы командной строки

Сначала нужно импортировать стандартный модуль sys:

import sys

Аргументы командной строки - это строки, хранящиеся в списке sys.argv:

n = len(sys.argv)
for i in range(n):
    print 'sys.argv[%d] = "%s"' % sys.argv[i]

Файлы

Открыть файл для чтения:

f = open('my_file.txt')

open() возвращает файловый объект с несколькими методами.
Как считать заданное число символов:

s = f.read(10)

Как считать весь файл целиком как строку:

s = f.read()

Как закрыть открытый файл:

f.close()

Как поочередно перебрать все строки в файле:

f = open('my_file.txt')
for line in f:
    print line
f.close()

Открытие файла для записи:

fw = open('out_file.txt', 'w')
fw.write('a line of text\n') # заметьте, что без '\n' здесь не обойтись
fw.write(a_string)
fw.close()

Другие действия над файлами: https://docs.python.org/2.5/lib/bltin-file-objects.html

Перед тем как проводить действия над именами файлов (например удалить файл), необходимо импортировать стандартные библиотечные модули, такие как os и os.path:

import os, os.path
if os.path.exists('my_file.txt'):
    os.remove('my_file.txt')

Все операции над именами файлов/каталогов из модулей os и os.path:

Любопытно посмотреть, как будет выглядеть алгоритм решения квадратного уравнения на Python, и сравнить его с эквивалентной версией для ALGOL.

Код на ALGOL Код на Python

begin
   real a,b,c,x1real,x2real,x1imag,x2imag,disc,sqroot;
   integer roots;
   a:=1;
   b:=-2;
   c:=1;
   if a=0 then
      begin
      roots:=1;
      x1real:=-c/b;
      x2real:=0;
      go to zeros
      end;
   roots:=2;
   disc:=b**2-4*a*c;
   if disc<0 then
      begin
      x1real:=x2real:=-b/(2*a);
      x1imag:=sqrt(-disc)/(2*a);
      x2imag:=-x1imag;
      go to output
      end;
   sqroot:=sqrt(disc);
   x1real:=(-b+sqroot)/(2*a);
   x2real:=(-b-sqroot)/(2*a);
zeros:   x1imag:=x2imag:=0;
output:   print(`A     B   C   X1REAL X1IMAG X2REAL X2IMAG ROOTS');
   print(a,b,c,` ',x1real,`  ',x1imag,`  ',x2real,`  ',x2imag,`  ',roots);
end
import math
a=1.
b=-2.
c=1.
if a==0:
    roots=1
    x1real=-c/b
    x2real=0.
    x1imag=0.
    x2imag=0.
else:
    roots=2
    disc=b**2-4.*a*c
    if disc<0:
        x1real=-b/(2.*a)
        x2real=-b/(2.*a)
        x1imag=math.sqrt(-disc)/(2.*a)
        x2imag=-x1imag
    else:
        sqroot=math.sqrt(disc)
        x1real=(-b+sqroot)/(2.*a)
        x2real=(-b-sqroot)/(2.*a)
        x1imag=0.
        x2imag=0.
print 'A     B   C   X1REAL X1IMAG X2REAL X2IMAG ROOTS'
print a,b,c,' ',x1real,'  ',x1imag,'  ',x2real,'  ',x2imag,'  ',roots

Что изменилось? Код на Python короче, но не принципиально - 26 строк вместо 29. Качественной разницы как при сравнении ассемблера и ALGOL здесь нет: и ALGOL и Python - языки высокого уровня. Тем не менее, код Python яснее, легче читается и изящнее выглядит. За счет чего? Во-первых, исчезли "лишние" символы: точки с запятой после каждой команды, двоеточия перед знаком равенства в операторах присвоения, ключевые слова begin/end, then. Во-вторых, в Python не нужно явно объявлять тип переменных в начале программы. В-третьих, в Python нет команды go to. Последнее изменение настолько важно, что на нем стоит остановиться подробнее.

Без оператора безусловного перехода go to - наследия машиных кодов и ассемблера - во времена расцвета ALGOL'а и Фортрана программирование было немыслимо. Неумеренное использование этой слишком сильной команды нередко приводило к появлению так называемого спагетти-кода - запутанных, трудных для понимания программ, напоминающих клубок спагетти. Конец этой вредной практике положил голландский ученый-программист Эдсгер Дейкстра, заявивший, что "квалификация программистов - функция, обратно зависящая от частоты появления операторов go to в их программах" (Dijkstra E. Go To Statement Considered Harmful // Communications of the ACM.- 1968.- Vol.11.- No.3.- Pp.147-148). В качестве альтернативы он предложил концепцию структурного программирования.

Основным элементом нового метода программирования стали блоки - например, несколько записанных подряд команд. Блоки служат для ограничения области видимости переменных и функций, их границы в Python задаются с помощью отступов. Далее, любую блок-схему можно выразить с помощью кода без оператора go to с помощью трех базовых управляющих конструкций: последовательности блоков, ветвления с помощью команды if, цикла. Последнее утверждение может быть доказано формально (теорема Бёма-Якопини). Все перечисленные конструкции должны иметь один вход и один выход. Повторяющиеся фрагменты программы можно и нужно оформить в виде подпрограмм.

Главным преимуществом, предопределившим успех структурного программирования, стало улучшение читаемости кода. Это основное направление эволюции языков программирования. В этом смысле Python подошел к идеалу очень близко.

Литература

  1. Программирование на Python (части 1-3) (Walters G.)
    Простое введение в основы языка Python: переменные, циклы, модули, функции и т.п. Любопытно, что эти уроки были опубликованы в свободном (!) электронном компьютерном журнале "Full Circle", издающемся энтузиастами дистрибутива Linux под названием Ubuntu.
  2. Python в научной работе (Hinsen K.)
    Сильно устаревшее, но возможно еще представляющее интерес обзорное введение в Python/Tk для ученых. Изначально курс предназначался для специалистов из Института структурной биологии (Гренобль, Франция).
  3. Дзэн Питона в примерах (Blanks H.)
    Дзэн Питона - это хорошо известный набор афоризмов, иллюстрирующих философию и принципы хорошего стиля Python. Сопроводить их примерами кода - удачная идея, помогающая начинающим программистам понять практический смысл "правил дзэн".

  4. Lambda в Python (Driscoll M.)
    Лаконичное введение в одну из самых сложных для начинающих функций Python. Приводится пример использования lambda в обратных вызовах (callbacks) Tkinter.

Занимательная математика: потеря ориентиров

В конце 19 - начале 20 века математика и тесно связанная с ней физика достигают своего триумфа: техническая революция - железная дорога, автомобиль, самолет, телефон и многое другое - доказали полезность и практическую значимость науки всем сомневающимся. Красивое, но бесполезное дитя древнегреческого гения ["Хотя геометрия ведет свое происхождение от практической деятельности - землемерия, греки воспринимали ее как интеллектуальную игру и большую часть их работ следует отнести к занимательной математике. В то же время их отношение к математике было более серьезным, так как они считали, что она отражает природу мира" (Singmaster D. The Unreasonable Utility of Recreational Mathematics)] вдруг обернулось Мидасом, превращающим в золото все, к чему бы ни прикасалось.

Одержимые жаждой военного могущества и богатства, ведущие государства мира берут под свой контроль систему образования. Приоритетом в ней вместо древних языков, истории и литературы становится математика - основа всех технических дисциплин. Старые христианские школы и университеты превращаются в интеллектуальные казармы, готовящие солдат, сержантов и генералов революции, разумеется научно-технической. Выпускается ранее не виданное и увеличивающееся с каждым годом количество учебников и пособий по математике. Чтобы заинтересовать и привлечь молодых людей к занятиям математикой, наиболее талантливые авторы начинают писать книги, посвященные занимательной математике.

Стоп! Почему на пике популярности и успеха вдруг так нужны стали книги, привлекающие внимание к математике? Сказки вроде "Волшебного Двурога" Сергея Боброва, приключенческие повести для детей как цикл Владимира Левшина о Магистре рассеянных наук или книги Мартина Гарднера и Якова Перельмана? Раньше как будто такого не было: начинающие математики читали Эйлера и им было интересно ["Лагранж говорит: "Если вы действительно любите математику, читайте Эйлера; изложение его сочинений отличается удивительною ясностью и точностью" (Литвинова Е.Ф. Леонард Эйлер. Его жизнь и научная деятельность).] Не означает ли бум "занимательной" математики, что остальная математика стала слишком сложной и скучной? И главный вопрос: занимаются ли современные ученые наукой в понимании мудрецов древней Греции?

Рассмотрим, чем была наука для древних греков:

"Из разнообразных рассказов о греческих мудрецах этого времени [середины I тысячелетия до нашей эры] можно видеть их бескорыстный интерес к окружающему миру. Они изучали движение светил, занимались геометрией, арифметикой, музыкой. Результаты, полученные в ходе этих ученых занятий, возможно, не превосходили достижений их восточных коллег. Астрономия вавилонян и геометрия египтян выглядит более развитой. Однако греческая наука обладала, по-видимому, с самого начала одной особенностью. В Вавилоне движение светил исследовалось ради астрологических предсказаний. В Египте геометрия изучалась преимущественно для нужд строительства, а также, возможно, для разметки полей. Арифметика была важна при хозяйственных и торговых расчетах. Греки, позаимствовав значительную часть своих знаний у египетских и халдейских мудрецов, отнеслись к этим знаниям несколько иначе. Они стали для них предметом бескорыстного интереса. Они сочли важным заниматься этими науками, не ожидая никаких практических результатов, а из любви к истине. Особенность греческой мудрости, в отличие от мудрости восточной, состояла в том, что знание было ценно само по себе. Оно представляло собой не свод практических рекомендаций, а незаинтересованное созерцание, имеющее в самом себе награду для созерцающего.

По-видимому, основным свойством такого созерцания должна быть ясность. Ход и взаимное расположение светил, свойства и отношения чисел или геометрических величин должны предстать уму в рамках завершенной, разом созерцаемой целостности. Поэтому теоретическое познание ориентировано не на добывание фактов, а на движение вглубь к скрытым свойствам, к прояснению невидимых пока деталей, которые бы позволили эту целостность обнаружить...

Нужно думать, что философия и теоретическая математика - во многом родственные предприятия духа...

Искусство [в смысле: ремесло.- Ф.З.] создает вещи, либо необходимые для выживания, либо доставляющие чувственное наслаждение. Наука же становится возможна тогда, когда человек не обременен необходимостью добывать себе пропитание и не поглощен заботой о новых удовольствиях. Это и означает, что стремление к ясности бескорыстно. Наука о первых началах есть удел свободного человека, который не обременен поиском пользы. Можно по-разному представлять себе такого человека. Не исключено, что он достаточно богат и может позволить себе не трудиться ради куска хлеба. Возможно, впрочем, что он вовсе не богат, а просто беззаботен и неприхотлив. Так или иначе, это человек, обладающий досугом, способный сам распоряжаться своим временем и своими усилиями. Ни другие люди, ни обстоятельства жизни над ним не властны, они не могут полностью подчинить его себе и заставить стремиться к внешним, навязанным извне целям" [Гутнер Г. Философия. Античные мыслители.- М.: Свято-Филаретовский православно-христианский институт, 2016. - 344 с.].

Созданная греками наука с полным основанием может быть названа занимательной в отличие от прикладной, чисто практической науки народов древнего Востока. Я вполне серьезно считаю, что в двадцатом веке мы вернулись к математике древних египтян и вавилонян. Не в смысле количества знаний, разумеется. Однозначно, мы знаем и умеем больше, чем даже Диофант и Архимед. Но наша математика - точно не бескорыстное занятие свободных людей, ищущих ясности. Нашим миром правят торгаши, которых по-настоящему интересуют только деньги, и многих они обратили в свою веру. Для них рыцари, пророки и мудрецы - лишние и никчемные люди, а высшее призвание математики - предсказывать колебания цен на нефть. В итоге сегодня наука стала точно таким же ремеслом как астрономия халдейских жрецов, составляющих гороскопы, и арифметика египетских писцов, подсчитывающих собранные налоги.

Занимательная математика 20 века, на мой взгляд, - это здоровая реакция человеческого духа на постепенную утрату идеалов, отчаянная попытка сохранить чистоту одной из самых красивых и глубоких тайн мироздания, открытых человеку, - математики.

Большая часть задач по программированию в этом курсе относится к занимательной математике. Это может показаться неправильным, ведь инженеры - люди практики, и интересовать их должны прежде всего приемы и методы, которые можно будет применить в работе. Но такой путь неизбежно приведет к необходимости создания новых специализированных курсов - "Python для инженеров химической промышленности", "Python для астрономов", "Python для инженеров-электронщиков" и т.п. С моей точки зрения, это - тупик, хотя подобные курсы или уже составлены или несомненно появятся в будущем. Занимательная математика - тот материал, на базе которого можно разрабатывать универсальный курс по инженерному искусству и программированию в целом.

Квадратные уравнения

Убедиться, что хорошо знакомые формулы


и

определяют корни квадратного уравнения, нетрудно. Для этого их нужно подставить в исходное уравнение ax2+bx+c=0 и выполнить несложные преобразования.

А вот как вывести эти формулы? Проще всего воспользоваться так называемым методом дополнения до полного квадрата (по-английски - completing the square). По сути это приведение квадратного трехчлена

ax2+bx+c

к виду

a(x-h)2+k,

где h и k - какие-то числа.

Есть простая формула из школьной алгебры для вычисления квадрата двучлена:

(x+p)2=x2+2px+p2.

Например:

(x+3)2=x2+6x+9 (p=3)

(x-5)2=x2-10x+25 (p=-5).

В любом полном квадрате коэффициент при x в два раза больше, чем число p, а постоянный член равен p2.

Рассмотрим следующий квадратный трехчлен:

x2+10x+28.

Он не является полным квадратом, потому что 28 - это не 5 в квадрате:

(x+5)2=x2+10x+25.

Тем не менее, первоначальный квадратный трехчлен можно записать как сумму этого полного квадрата и константы:

x2+10x+28=(x+5)2+3.

Это называют дополнением до полного квадрата.

Для любого заданного приведенного квадратного трехчлена

x2+bx+c

можно записать квадрат, который будет иметь точно такие же первые два члена:

Этот квадрат отличается от первоначального квадратного трехчлена только постоянным членом. Поэтому можно записать:

x2+bx+c=(x+b/2)2+k,

где k=c-b2/4. Например:

x2+6x+11=(x+3)2+2

x2+14x+30=(x+7)2-19

x2-2x+7=(x-1)2+6.

Теперь вернемся к исходному квадратному уравнению ax2+bx+c=0. Разделим все его члены на коэффициент a:

Считаем, что a≠0, иначе уравнение превратится в линейное. Применим к полученному приведенному уравнению технику дополнения до полного квадрата. Вычтем сначала из левой и правой части уравнения c/a. Получаем:

Далее, добавим к каждой части уравнения константу, которая превратит левую часть в полный квадрат.

что дает:

Приводим слагаемые в правой части к общему знаменателю:

В левой части уравнения получился полный квадрат. Извлечем квадратный корень из обеих частей:

Наконец, оставляем в левой части только неизвестное x и получаем хорошо известную формулу:

Интересно, что таким способом решали квадратные уравнения в древнем Вавилоне примерно за 1600 лет до Христа. В Британском музее есть глиняная табличка 13901 с задачами на квадратные уравнения с решениями. Вот одна из этих задач:

"Я прибавил к площади сторону моего квадрата. Получилось ¾. Найти сторону квадрата".

В современных обозначениях (кроме того, вавилоняне для записи чисел использовали 60-ричную систему счисления) задачу можно записать так:

ax2+bx=c; a=1, b=1, c=¾.

В древнем документе предлагается следующий способ решения [Berriman A.E. The Babylonian Quadratic Equation // The Mathematical Gazette.- 1956.- Vol.40.- No.333.- Pp.185-192]:

Текст Формула
1
b
½·1=½
b/2
(½)2
(b/2)2
¼+¾=1
(b/2)2+c=Z
=12
=(√Z)2
1-½=½
Z-(b/2)=x

Очевидно, что способ древних вавилонян и метод дополнения до полного квадрата - это одно и то же.

Формулировка условий задачи в терминах геометрических величин естественным образом подталкивает к геометрической интерпретации этого решения (рис.1.5), хотя сами древние вавилоняне так скорее всего не делали.


Рис.1.5. Геометрическая интерпретация решения квадратного уравнения

Теперь несколько занимательных задач на квадратные уравнения. Конечно, их можно решить и вручную без всякого программирования.

  1. Задача про пчелиный рой средневекового индийского математика и астронома Бхаскара II из трактата "Венец астрономического учения" (задача про обезьян из раздела "Модели и алгоритмы" - оттуда же):

    "Корень квадратный из половины пчелиного роя полетел к кусту жасмина. Восемь девятых роя остались дома. Одна пчелка полетела за трутнем, обеспокоенная его жужжанием в цветке лотоса, куда он попал вечером, привлеченный приятным ароматом, и не может оттуда выбраться, так как цветок закрылся. Скажи мне число пчел роя".

    Обозначим неизвестное число пчел в рое через x. Тогда по условию задачи можно составить следующее уравнение:

    От квадратного корня лучше избавиться, произведя замену переменной:

    Тогда x=2y2, и уравнение примет вид:

    или

    2y2-9y-18=0.

    Решив его, получим два значения для y:

    y1=6, y2=-3/2.

    Вычисляем соответствующие значения x:

    x1=72, x2=4,5.

    Так как число пчел должно быть целое и положительное, то удовлетворяет задаче только первый корень: рой состоял из 72 пчел. Проверим:

  2. Старинные задачи про яйца

    Стендаль - известный французский писатель первой половины XIX века, участник похода Наполеона на Москву - оставил любопытное воспоминание о том, как он изучал алгебру в школе:

    "Шабер [новый учитель математики в Центральной школе Гренобля, где учился юный Стендаль.- Ф.З.] был действительно меньшим невеждой, чем Дюпюи. Я нашел у него Эйлера с его задачами о числе яиц, которые крестьянка несла на рынок, когда вор украл у нее одну пятую часть, а она потом оставила половину остатка, и т.д., и т.д.

    Это было для меня открытием. Я понял, что значит пользоваться орудием, называемым алгеброй. Но, черт возьми, никто мне об этом ничего не говорил. Дюпюи постоянно изрекал на этот счет напыщенные фразы, но ни разу не произнес этих простых слов: это то самое разделение труда, которое производит чудеса, как всякое разделение труда, позволяя уму направить все свои силы на одну сторону предметов, на одно из их свойств.

    Все пошло бы для нас иначе, если бы Дюпюи сказал нам: "Этот сыр мягкий или жесткий; он белый или голубой; старый или молодой; мой или твой; легкий или тяжелый. Из всех этих свойств будем рассматривать только вес. Каков бы ни был этот вес, назовем его А. Теперь, забыв о сыре, применим к А все то, что мы знаем о количествах".

    Такую простую вещь никто не мог нам сказать в этой далекой провинции; впоследствии, вероятно, провинция испытала на себе влияние Политехнической школы и идей Лагранжа" (Стендаль. Жизнь Анри Брюлара).

    Свою автобиографию Стендаль писал уже после 50 и не мудрено, что он мог ошибиться в мелких деталях. В "Универсальной арифметике" Эйлера (эта книга сначала была переведена с немецкого на русский, а потом и на многие другие европейские языки; в английском переводе эта книга называлась "Elements of Algebra") - первом и очень хорошем учебнике алгебры на русском языке - действительно есть задача о крестьянках, продающих яйца:

    "Двѣ крестьянки несутъ на рынокъ 100 яицъ, у одной больше нежели у другой; денегъ же выручаютъ поровну. Первая говоритъ другой ежели бы твои яицы были у меня, то бы выручила я 15 крейцеровъ, на что другая ответствуетъ, а ежели бы твои яицы имѣла я, тобы я за нихъ взяла 6⅔ крейцера; спрашивается сколько у каждой было?

    Положимъ что первая имѣла x яицъ, то другая 100-x, чего ради ежели бы первая 100-x продала за 15 крейцеровъ, то поставь тройное правило

    100-x : 15 = x : 15x/(100-x) крейцеровъ: [первая крестьянка продавала яйца по цене 15/(100-x) за штуку и, продав x яиц, всего выручила за них 15x/(100-x) крейцеров] подобнымъ образомъ надлежитъ поступать и въ другомъ случаѣ, то есть, когда другая x яицъ продать хотѣла за 6⅔ крейцера, найти можно, сколько она за свои 100-x яицъ выручила, а имянно:

    x: 20/3 = 100 - x : (2000-20x)/3x крейцер.; [вторая крестьянка продавала яйца по цене 6⅔:x=20/3x за штуку и, продав 100-x яиц, всего выручила за них (2000-20x)/3x крейцеров]

    и поелику обѣ крестьянки выручили поровну, то будетъ у насъ уравненiе

    которое умножь на 3x будетъ

    45xx/(100-x)=2000-20x

    умножь еще на 100-x получится

    45xx=200000-4000x+20xx,

    вычт. 20xx останется 25xx=200000-4000x раздѣли на 25, выдетъ xx=-160x+8000, и слѣдовательно x=-80+√6400+8000 или x=-80+120=40.

    Отвѣтъ. У первой было 40 яицъ, а у другой 60, и каждая изъ нихъ выручила 10 крейцеровъ" (Л.Эйлер. Универсальная арифметика).

    Однако, ни про каких воров, укравших яйца, в задаче Эйлера не говорится. Возможно, Стендаль решал и другие задачи про яйца, например из задачника известного в то время немецкого математика и педагога Майера Хирча (1770-1851):

    "Крестьянин понес яйца на рынок. По дороге 10 из них было украдено. ⅘ от оставшегося их количества минус 2 яйца он разбил. Крестьянин докупил еще 53 яйца, и их у него стало на 11 штук меньше, чем в самом начале. Сколько яиц у крестьянина было в самом начале?" [Ответ: 80 яиц] (M.Hirsch. A Collection of Arithmetical and Algebraic Problems and Formulae).

    Но эта задача, хотя и алгебраическая, не приводит к квадратному уравнению.

  3. Картина Николая Богданова-Бельского "Устный счет. В народной школе С. А.Рачинского"

    Рис.1.6. Богданов-Бельский Н.П. Устный счет. В народной школе С.А.Рачинского (1895)

    Эту картину можно было встретить в советских школьных учебниках, поэтому многим она знакома. Гораздо меньше известен изображенный на полотне учитель - Сергей Александрович Рачинский (1833-1902) - человек совершенно замечательный.

    "Снова осмеливаюсь явиться просителем к Вашему Императорскому Величеству - выпрашивать пособие доброму делу.

    Вы изволите припомнить, как несколько лет тому назад я докладывал Вам о Сергее Рачинском, почтенном человеке, который, оставив профессорство в Московском университете, уехал на житье в свое имение, в самой отдаленной лесной глуши Бельского уезда Смоленской губернии, и живет там безвыездно вот уже более 14 лет, работая с утра до ночи для пользы народной. Он вдохнул совсем новую жизнь в целое поколение крестьян, сидевших во тьме кромешной, стал поистине благодетелем целой местности, основал и ведет, с помощью 4 священников, 5 народных школ, которые представляют теперь образец для всей земли. Это человек замечательный. Все, что у него есть, и все средства своего имения он отдает до копейки на это дело, ограничив свои потребности до последней степени. Между тем дело разрастается у него под руками, и он уже вынужден сокращать его за недостатком средств.

    Кроме школ он устроил у себя специальную больницу для сифилиса, который, как известно, составляет у нас в иных местностях язву населения по деревням, передаваясь наследственно от одного поколения другому. Эта больница чрезвычайно полезна; но, к сожалению, и она должна закрыться.

    "Увы!- писал мне Рачинский в декабре прошлого года,- эта затея слишком дорогая, чтоб я мог надеяться получить откуда-либо средства: на ее дальнейшую поддержку. Ее годовой бюджет - 600 рублей (фельдшер - 300, содержание больных - 200, прислуга, медикаменты, освещение - около 100 руб. Отопление дает брат). Но мало того,- временное помещение никуда негодно; нужна постройка, которая обойдется рублей в 1.500. В больнице 4 кровати, занятые постоянно, лечилось в течение 9 месяцев у меня 21 человек; дома - около 90. Дело несомненно полезное,- сифилис, кроме случаев исключительных, излечим наверное (фельдшер отличный, шесть раз в год приезжает врач). Но это дело я не могу продолжать иначе, как в долг. Это безумие, на которое я решился - и теперь сам не знаю, как быть".

    А на днях он пишет: "Тяжкое, но необходимое дело - привесть в порядок мой бюджет... Закрытие больницы последует в мае (зимою рука не поднимается - так много больных)".

    Простите, Ваше Величество, что утруждаю Вас чтением всего вышеписанного. Мысль моя такова: покуда жив еще человек, умеющий вести такое доброе для народа дело и полагающий в него свою душу,- стоит поддержать его. Вы мне дозволили просить, и я решаюсь на сей раз. Не благоволите ли, для поддержания этой больницы, пожаловать 2.000 рублей, из коих 1.500 пойдет на строение, а 500 на содержание в течение года? Этот дар Вашего Величества ободрит и оживит радостью всех трудящихся в этом деле.

    Долгом почитаю прибавить, что сам Рачинский и в мысли не имеет чего-либо просить, ожидать или надеяться от щедрот Вашего Величества.

    Константин Победоносцев

    1 февраля 1883"

    Это письмо написано тем самым Победоносцевым - воспитателем Александра III и Николая II, обер-прокурором Святейшего Синода, одним из самых влиятельных людей Российской империи. Победоносцев и Рачинский были близкими друзьями. Художник Богданов-Бельский был одним из учеников школы Рачинского.

    Сергей Александрович сам учил крестьянских детей русскому языку, арифметике, ботанике, проводил занятия по черчению и рисованию, а также по музыке и пению. Если присмотреться к картине, можно заметить висящие на стене нотный ряд и эскиз работы В.Васнецова "Богоматерь с Младенцем". При обучении арифметике из практических соображений главное внимание уделялось решению задач в уме. "С поля за бумагой и карандашом не побежишь. Решать надо умственно,"- говорил Рачинский (Маркова Т. С поля за карандашом и бумагой не побежишь). Вот, что писал о своей методике сам педагог:

    "Къ тому же мною давно замѣчено, что огромное большинство учителей затрудняется изобрѣтенiемъ сколько-нибудь сложныхъ ариөметическихъ задачъ. Происходитъ это не отъ недостатка воображенiя и изобрѣтательности, а отъ недостаточнаго знакомства съ числами. На эту скромную область ариөметическаго знанiя при подготовкѣ учителей вообще мало обращается вниманiя. Между тѣмъ нѣкоторое освоенiе съ нею въ высшей степени облегчаетъ трудъ элементарнаго преподаванiя ариөметики. Что касается собственно изобрѣтенiя задачъ, то для него даетъ неизчерпаемый матерiалъ уже одно знакомство съ числами первой тысячи. Само собою разумѣется, что знакомство это должно быть твердое и полное, въ особенности относительно знаменательныхъ чиселъ нашихъ системъ мѣръ и вѣсовъ. Для учителя, напримѣръ, не безразлично что число 40 не только =23.5, но также =30+31+32+33, что 365 не только =5.73, т.е. 5(80+81+82), но также =102+112+122=132+142=(172+212)/2, и т.д.

    Знакомство съ числами первой тысячи прiобрѣтается легко, при нѣкоторомъ вниманiи и старанiи. Пишущiй эти строки, приступившiй къ преподаванiю ариөметики на пятомъ десяткѣ своихъ лѣтъ, прiобрѣлъ его довольно быстро слѣдующими двумя простыми прiемами. Онъ поставилъ себѣ за правило рѣшать въ умѣ, во время уроковъ всякую письменную задачу, рѣшаемую учениками,- и разлагать въ умѣ на первоначальные множители всякое число, не слишкомъ крупное, попадающееся ему на глаза. Само собою разумѣется, что въ молодые годы знакомство съ числами прiобрѣтается гораздо легче, чѣмъ въ возрастѣ зрѣломъ.

    Что касается до пользы, которую приносятъ ученикамъ упражненiя въ умственномъ счетѣ, то ее не слѣдуетъ преувеличивать. Способность къ нему - способность весьма спецiальная и отъ другихъ независимая, нерѣдко сильно развитая въ дѣтяхъ ума самаго ограниченнаго. Тѣмъ не менѣе, способность эта полезна, и въ отношенiи практическомъ, и какъ средство для здоровой умственной гимнастики. Въ особенности можно сказать послѣднее относительно навыка мысленно обращаться съ прямоугольными поверхностями и объемами, доступными созерцанiю дѣтей и безъ систематической геометрической подготовки" (С.Рачинский. 1001 задача для умственного счета).

    Обратимся к задаче, изображенной на картине Богданова-Бельского. Требуется устно, в уме найти результат вычислений по формуле:

    В приведенном выше отрывке сам Сергей Александрович дает подсказку, как нужно решать этот пример. Он подметил любопытное свойство ряда чисел: 102+112+122=132+142. Чему равны квадраты 10, 11 и 12, многие помнят еще со школы. В уме вычисляем: 100+121+144=365. Этому же числу должна быть равна сумма 132+142. Значит, (102+112+122+132+142)/365=(365+365)/365. Ответ будет 2.

    Зададимся теперь вопросом: есть ли другие ряды из пяти последовательных чисел, сумма квадратов первых трех из которых равна сумме квадратов двух последних?

    Обозначим первое число из этой последовательности через x. Тогда получится уравнение

    x2+(x+1)2+(x+2)2=(x+3)2+(x+4)2

    Раскроем скобки, приведем подобные слагаемые, собрав все члены уравнения в левой части:

    x2-8x-20=0.

    Откуда:

    x1=10, x2=-2.

    Следовательно, существует два ряда, удовлетворяющих поставленному условию: ряд Рачинского

    10, 11, 12, 13, 14

    и ряд:

    -2, -1, 0, 1, 2.

    Действительно,

    (-2)2+ (-1)2+02=12+22=5.

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

  4. Какие числа?

    Эта задача напоминает предыдущую:

    "Найти три последовательных числа, отличающихся тем свойством, что квадрат среднего на 1 больше произведения двух остальных.

    Решение

    Если первое из искомых чисел х, то уравнение имеет вид

    (х+1)2=х(х+2)+1.

    Раскрыв скобки, получаем равенство

    х2+2х+1=х2+2х+1,

    из которого нельзя определить величину х. Это показывает, что составленное нами равенство есть тождество; оно справедливо при любом значении входящей в него буквы, а не при некоторых лишь, как в случае уравнения. Значит, всякие три последовательных числа обладают требуемым свойством. В самом деле, возьмем наугад числа

    17, 18, 19.

    Мы убеждаемся, что

    182-17·19=324-323=1.

    Необходимость такого соотношения выступает нагляднее, если обозначить через х второе число. Тогда получим равенство

    х2-1=(х+1)(х-1),

    т.е. очевидное тождество" (Я.Перельман. Занимательная алгебра).

  5. Первый круг

    Закончился первый круг чемпионата СССР по футболу. Каждая команда сыграла с каждой по одному матчу. Всего было сыграно 66 матчей. Сколько команд участвует в турнире?

    Обозначим неизвестное число команд через х. Каждая команда сыграла (х-1) матчей, так как сама с собой играть она не может. При этом нужно учесть, что когда "Динамо" играет со "Спартаком" и "Спартак" играет с "Динамо", так что общее число всех матчей будет вдвое меньше, чем х(х-1). В итоге получаем уравнение:

    х(х-1)/2=66.

    После несложных преобразований имеем:

    х2-х-132=0,

    откуда

    x1=12, x2=-11.

    Отрицательный корень не имеет смысла с точки зрения условий задачи и его можно отбросить. Остается единственное решение: 12 команд. Столько команд участвовало в турнирах 1945-1946 и 1955-1959 гг.

Все эти задачи просты, интересны, правда несколько искусственны. Однако, квадратичные зависимости и, следовательно, квадратные уравнения встречаются и в явлениях природы, например в тех, которые описываются законами обратных квадратов. Это тип законов, утверждающих, что определенный вид энергии или его интенсивность уменьшается пропорционально квадрату расстояния от источника энергии. К ним относятся закон всемирного тяготения, закон Кулона, зависимости для интенсивности света, звука и т.п. Выводится закон обратных квадратов очень просто. Представим себе точечный источник какого-либо вида энергии (гравитационной, электромагнитной, звуковой). Поток энергии будет исходить от него во всех направлениях в трехмерном пространстве. Расстояние от источника r - это радиус сферы, в центр которой помещен источник. Суммарное количество энергии, испускаемой источником, в каждый момент времени постоянно, но с увеличением расстояния от источника оно будет распределяться по площади поверхности сферы S=4πr2 все большего размера. Отсюда, из пространственного устройства нашего мира, и получается обратная квадратичная зависимость от расстояния.

Литература

  1. Перельман Я.И. Занимательная алгебра.- М.: Государственное издательство технико-теоретической литературы, 1955.- 184 с.
  2. Попов Г.Н. Сборник исторических задач по элементарной математике.- М.-Л.: ОНТИ, 1938.- 216 с.
  3. Универсальная ариөметика Г. Леонгарда Ейлера. Том вторый, въ которомъ предлагаются правила, рѣшенiя уравненiй, и Дiофанскiй образъ рѣшить вопросы.- Императорская Академiя Наукъ, 1769.- 586 с.
  4. Рачинскiй С.А. 1001 задача для умственнаго счета.- С.-Петербургъ: Сѵнодальная Типографiя, 1899.- 88 с.

Законы и наблюдения

Рассмотренные в предыдущем разделе задачи, как забавные, так и на использование фундаментальных физических законов, решаются по одному алгоритму, то есть имеют одинаковое математическое содержание и отличаются лишь сюжетом. Неожиданно, не так ли: закон, определяющий притяжение всех тел во Вселенной, и история про крестьянок, продающих яйца на базаре, фактически равнозначны. Выходит, что границы между занимательной математикой и открытием великих законов физики нет.

Зато она определенно есть между поиском фундаментальных законов природы и применением математики в инженерных дисциплинах. Во всяком случае, ее видел и считал принципиально важной Платон:

"Все помнят знаменитую аналогию в "Государстве" Платона, где мир сравнивается философом с темной пещерой, а люди - с узниками, прикованными спиной к свету таким образом, что они могут видеть только тени вещей и следить за их движением. Платон описывает, как эти узники считали реальными только тени и пытались открыть закономерности в их движении. Когда один из узников освободился, он получил возможность увидеть свет и вещи такими, каковы они есть в действительности. Платон описывает, с каким сожалением и презрением этот увидевший новый мир человек думает теперь о своем прежнем плене и об изучении теней. В заключении этой аналогии философ говорит о различных науках, об изучении чисел, искусстве измерения, изучении звезд. Он различает четыре ступени познания: высшая ступень называется ἑπιστήμη и соответствует знанию истинных вещей, познанию их сущности, как это описано в аналогии. Вторая ступень называется рассудочным познанием (διάνοια) и может быть достигнута путем изучения наук. Две последние ступени относятся к первым двум, как предположение относится к знанию. Они называются доверием (πίστις) и догадкой (εικασια). В нашей проблеме возможности физического "объяснения" природы мы касаемся главным образом различия между первыми двумя ступенями познания. Поясним на простом примере, что можно понимать под этими ступенями. Допустим, что человек, которого мы, как нам казалось, хорошо знаем, неожиданно совершает преступление. Сначала нам это покажется совершенно невероятным. Мы могли бы затем узнать, почему он так поступил, от тех людей, которым известны все подробности этого случая; мы могли бы ознакомиться со всеми аргументами и после тщательных их исследований были бы в состоянии понять совершенное преступление. Это понимание соответствует рассудочному познанию (διάνοια). Но могло бы оказаться, что нам сразу стало ясно, что этот человек должен был именно так поступить. Такого рода знание соответствует тому, что Платон называет ἑπιστήμη.

Вернемся теперь к науке о природе. Caм Платон очень подробно объясняет, что представляет собой вторая, низшая ступень познания и как мы в процессе изучения природы можем достигнуть этой ступени. Наиболее важными ему кажутся, прежде всего, математические законы природы, находящиеся за явлениями, а не сам многогранный мир явлений. Никакая другая задача науки о природе не кажется ему столь существенной, как задача открытия неизменных законов в постоянно меняющихся явлениях. Очень важно и показательно, что Платон так сильно подчеркивает именно эту, как мы ее теперь иногда называем, "формальную" сторону науки.

В одном месте, например, Платон говорит о пифагорейцах и их исследованиях гармоний и колебаний струн. Единственно существенным в их экспериментах является для него мысль о численных отношениях, лежащих в основе гармонических звучаний; явления же сами по себе остаются несущественным дополнением. Но познание природы, которое, таким образом, может быть достигнуто путем изучения ее математической структуры, представляет собой, согласно Платону, всегда только прелюдию к мелодии, являющейся именно целью изучения, преддверием к раскрытию "сущности" вещей, к достижению высшей ступени познания. Кто забывает это обстоятельство, тот уподобляется тем узникам в изображении Платона, которые воспринимают движение теней как саму действительность и никогда не увидят подлинного света. Насколько важно было для Платона противопоставление этого "истинного" познания методам обычной науки о природе, ясно из того высказывания о пленниках, которое он в своей аналогии вкладывает в уста человека, познающего действительность. Платон пишет:

"Не думаешь ли ты, что вспоминая о своей первой жизни, о той мудрости и о тех узниках, он сочтет свою перемену счастливой, а о других [оставшихся в пещере] будет жалеть?.. Вспоминая также о почестях и похвалах, которые возданы были друг другу, и о наградах тому, кто с проницательностью смотрел на происходящее и лучше других замечал, что бывает сначала, что потом или что идет вместе и, исходя из этого, обладал особой способностью угадывать, что должно быть, - как ты думаешь, будет ли он желать того же и станет ли он завидовать людям, которые у них считаются почетными и влиятельными..." [Platonis. Rei publicae libri gesem, 1884, 516, c и d, стр.204]

...Отправной пункт физики Галилея является абстрактным и лежит как раз на том пути, который Платон предначертал для науки о природе. Аристотель еще описывал реальное движение тел в природе и установил, например, что легкие тела в общем падают более медленно, чем тяжелые. Галилей же поставил совершенно другой вопрос: как могли бы падать тела, если бы не было никакого сопротивления воздуха? Как падают тела в пустом пространстве? Галилею удалось сформулировать математические законы этого теоретически воображаемого движения, которое в эксперименте могло быть реализовано всегда тoлько приблизительно. Вместо непосредственного рассмотрения совершающихся вокруг нас процессов природы появилась математическая формулировка предельного закона, который может быть проверен только при экстремальных условиях. Возможность вывести из природных процессов простые и точно формулируемые законы покупается ценой отказа от непосредственного применения этих законов к явлениям природы" [Гейзенберг В. Философские проблемы атомной физики.- М.: Издательство ЛКИ, 2008.- С.25-28].

В отличие от Платона мы никаких границ между "задачей открытия неизменных законов в постоянно меняющихся явлениях" и практическим их применением видеть не привыкли: и то и другое называют наукой. Но это не одно и то же. С занимательной математикой поиск законов природы роднит определенная искусственность в постановке задачи и сравнительная простота.

Почему греческая математика - своего рода интеллектуальное развлечение - сыграла столь важную роль в современной научно-технической революции? Для чего все крупные математики и по сей день занимаются совершенно оторванными от жизни задачами занимательной математики?

Ответ: как раз из-за отмеченного родства математики занимательной и математики, стоящей за фундаментальными законами физики. И там и там целью является получение простых математических соотношений, стоящих за причудливой игрой чисел, наблюдаемых в явлениях окружающего мира. Разве не похожи поиски законов природы на решение головоломки? Такого рода цели самодостаточны, от их осуществления не ждут никакой практической отдачи, а только радости творчества.

Окружающий мир подчиняется строгим и простым математическим законам. После того, как они были открыты "искателями истины", можно пытаться с их помощью моделировать природные явления и создавать полезные устройства. Формулировки этих законов достаточно просты. Но проявляются они в явлениях реального мира чаще всего весьма сложным образом. Подавляющее большинство практических задач, стоящих перед наукой,- нерешаемы, в том смысле, что для них нельзя получить точное аналитическое решение. Задачи же занимательной математики - решаемы, благодаря своей сравнительной простоте (как решаема и задача обнаружения базовых законов физики). Решая их, математик получает опыт, который он не смог бы приобрести, имея дело только с практическими проблемами. Много ли ученые сумели бы узнать о законах движения тел, учитывай они сопротивление воздуха? Пожалуй, так и считалось бы, что летящую стрелу толкает сзади стремительно обтекающий ее воздух, как думал Аристотель. Или, если взять военные действия: смоделировать их достоверно с учетом всех факторов - невозможно. Другое дело - шахматы, которые благодаря своей сравнительной простоте поддаются формализации и компьютерному анализу (имеется в виду перебор вариантов в поисках оптимального).

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

Почему нам - инженерам и исследователям сегодняшнего или завтрашнего дня - нужно учитывать разницу между поиском фундаментальных законов и созданием машин для облегчения жизни в этом мире?

Открытие законов физики, как и геометрия Евклида или изучение географии Земли,- предприятие, почти завершенное. Простые универсальные точные аналитические решения в инженерных науках почти все известны, вряд ли в будущем будет открыто много новых. Все оставшиеся прикладные задачи, которые нужно решать, придется решать по-другому: используя сложные компьютерные модели, метод перебора вариантов, инженерную интуицию, эмпирические постоянные, непроверяемые гипотезы и другой инструментарий, который не был нужен при создании классической физики. Результатом подобного поиска всегда будет не новый закон природы, а частное решение, которое может пригодиться для создания нужного устройства. Для следующего полезного устройства всю работу придется делать заново: проводить новые эксперименты, программировать другие компьютерные модели и надеяться, что предыдущий опыт будет чем-то полезен.

Если поиск законов природы - это пазл, который можно сложить единственным образом, то решение сложных практических задач - это выкладывание из разноцветных кусочков стекла узоров мозаики, которые каждый раз выходят разные. Каждое такое решение - это не новый закон, а новое наблюдение над сложными явлениями. Наблюдения можно обобщать, анализировать, сравнивать друг с другом, но они никогда не будут столь же универсальными как законы природы.

Ясно, почему прикладные научные дисциплины множатся и растут до бесконечности. Нет конца разнообразию практических задач, а значит нет конца и процессу специализации. Тотальная ориентация современного общества на практику (государствам нужна новая техника и связанные с нею прибыли) неизбежно ведет к разрушению целостности образования и мировоззрения, мучительному для человеческой души. Это небезобидный процесс. В конечном итоге он приведет к деградации нашей технической цивилизации в целом, потому что не будет хватать глубоко понимающих реальность людей. Одних узких специалистов недостаточно даже для развития техники, не говоря уже об общественной жизни в целом.

Выход, на мой взгляд,- в возвращении в образование идеалов древнегреческих и средневековых философов. Обучение на уровне среднего образования надо ограничить семью свободными искусствами и изучением фундаментальных законов природы. Школа должна учить мышлению, а не набору знаний. Ботаника, география, зоология и т.п. эмпирические предметы не должны быть обязательными. Вместо этого пусть дети читают Брема и Жюля Верна. Подготовку инженеров и исследователей в университетах нужно начинать с основательного знакомства с занимательной математикой и фундаментальными законами природы с элементами философии и только потом постепенно переходить к изучению фактов и к инженерной практике в избранной области техники. Не следует смешивать изучение законов природы с их практическим приложением и изучением реальных явлений. Этому должны быть посвящены разные учебные дисциплины.

2. Функция

Библиотека научной графики Matplotlib

Сила Python - в его внешних библиотеках, невероятно расширяющих возможности языка. Один из самых интересных и полезных проектов такого рода - библиотека научной графики Matplotlib, разработанная американским нейробиологом Джоном Хантером (к сожалению, он умер в 2012 г. от рака). Графики, рисуемые Matplotlib,- очень хорошего, полиграфического качества, их вполне можно вставлять в научную статью или монографию.

Быстрее всего испытать в деле Matplotlib можно с помощью командной строки IDLE. Последовательно введем в нее три команды (рис.2.1), не забывая всякий раз нажимать [Enter] и дожидаться появления значков >>> . Первая команда импортирует часть библиотеки Matplotlib под названием pyplot и присваивает ей более короткое имя plt. Вторая команда формирует график, состоящий из точек со следующими координатами y: [1,3,2,5]. По умолчанию Matplotlib для координат x возьмет значения: [0,1,2,3]. Третья команда выводит полученный график на экран.

Рис.2.1. Применение Matplotlib в командной строке

Должно появиться новое окно с графиком (рис.2.2).

Рис.2.2. Простейший график Matplotlib, полученный из командной строки

Обратите внимание на кнопки, расположенные в верхней части окна: они бывают очень полезны. Разработчики Matplotlib визуально разделили их на три группы по функциональности.

Первая группа - - навигационные кнопки. Кнопки со стрелками аналогичны кнопкам "Вперед" и "Назад" интернет-браузеров. Кнопка с "домиком" возвращает графику первоначальный вид, отменяя все сделанные модификации.

Вторая группа - - кнопки, управляющие параметрами отображения графиков. Кнопка с "крестом" позволяет перемещать график внутри координатных осей без изменения масштаба. "Лупа" дает возможность разглядеть детали графиков.

В третью группу входит одна единственная кнопка - , с помощью которой можно сохранить получившийся график в виде графического файла с расширением *jpg, *.tif, *.png, *.pdf и т.д. Такой рисунок можно потом вставить в документ Word или разместить на html-странице в Интернете.

Поиграйте с этими кнопками.

Итак, команды Matplotlib, как и обычные команды Python, можно вводить прямо в командной строке интерпретатора и исполнять одну за другой, но в дальнейшем мы будем программировать графики в отдельных файлах - так удобнее и в конечном счете быстрее.

Цель работы

Конечная цель работы - построить график заданной функции, определив цвет графика, стиль линии и добавив легенду (пояснение) с формулой этой функции в нотации TeX. Для этого нужно изменить предлагаемый ниже пример-шаблон, предварительно скопировав его в буфер обмена и вставив в окно программ IDLE (т.е. его нужно запускать как отдельную программу из IDLE).

Не нужно стараться понять весь код до мелочей. Достаточно, используя пример в качестве образца, понять, как его изменить, чтобы решить поставленную задачу.

Пример

Так можно построить график функции f(x)=sin(x)/x:

# -*- coding: UTF-8 -*-

# Импортируем стандартную, "внутреннюю" библиотеку math
import math

# Импортируем один из пакетов "внешней" библиотеки Matplotlib
import matplotlib.pyplot as plt

# Импортируем еще один пакет со вспомогательными функциями
from matplotlib import mlab

# Будем рисовать график этой функции
def func(x):
    """
    sinc(x)
    """
    if x==0:
        return 1.0
    return math.sin(x)/x

# Интервал изменения переменной по оси X
xmin=-20.0
xmax=20.0

# Шаг между точками
dx=0.01

# Создадим список координат по оси X на отрезке [xmin; xmax],
# включая концы
xlist=mlab.frange(xmin, xmax, dx)

# Вычислим значение функции в заданных точках
ylist=[func(x) for x in xlist]

# Рисуем график заданного цвета (color) и стиля (linestyle),
# с определенной формой маркера (marker), помечающего отдельную точку
plt.plot(xlist, ylist, color='b', linestyle='-', marker='', label="$\\frac{sin(x)}{x}$")

# Выводим легенду, описанную в предыдущей команде в значении параметра label
plt.legend(title=u"Функция")

# Покажем окно с нарисованным графиком
plt.show()

Рис.2.3. График функции sin(x)/x

Задание

Построить график одной из нижеперечисленных функций с заданными цветом, стилем линии и формой маркера; указать в легенде формулу функции в формате TeX; полученный график вставить в файл Word.
  1. y=math.log(x) - синий, сплошная линия, кружок

  2. y=math.sqrt(x) - черный, штриховая линия, треугольник вершиной вверх

  3. y=math.cosh(x) - гиперболический косинус - желтый, пунктирная линия, треугольник вершиной вниз

  4. y=math.sinh(x) - гиперболический синус - зеленый, штрихпунктирная линия, квадратик

  5. y=(4.*x**3-6.*x**2+1.)*math.sqrt(x+1)/(3.-x) - красный, пунктирная линия, шестиугольник

  6. y=2.*math.pow(x,1.5) - полукубическая парабола - пурпурный, сплошная линия, косой крест

  7. y=2.*x**3.+x*x-5*x+7. - кубическая парабола - голубой, сплошная линия, прямой крест

Вопросы

  1. В чем разница между библиотеками math и Matplotlib с точки зрения программиста?

  2. Для чего в теле функции func(x) нашего примера стоит оператор условия? Что будет, если его убрать?

Литература

  1. Использование библиотеки Matplotlib (Ильин Е.)
    Серия шпаргалок, в каждой из которых находится короткий пример, акцентирующий внимание на какой-то одной возможности библиотеки.
  2. Matplotlib (pylab) простые вещи 2 (Колдунов Н.)
    Вольные переводы избранных отрывков документации к Matplotlib.
  3. Sandro Tosi. Matplotlib for Python Developers. Birmingham-Mumbai: PACKT Publishing, 2009.- 293 p.
    Книга идеально подходит для начинающих изучать Matplotlib: доступный английский язык, ясный код примеров на Python, много простых примеров и справочной информации.
  4. Alexandre Devert. matplotlib Plotting Cookbook. Birmingham-Mumbai: PACKT Publishing, 2014.- 205 p.
    Свыше 60 простых рецептов использования Matplotlib в практике ученого-исследователя (например, как визуализировать обтекание круглого цилиндра).
  5. Использование LaTeX для набора формул на форуме / Интернет-сайт "Физика в анимациях"

  6. Котельников И.А., Чеботаев П.З. LATEX по-русски. Новосибирск: Сибирский хронограф, 2004.- 496 с.
    Книга хорошо подходит для изучения LATEX, если вам понадобится или захочется с помощью этой системы подготовить для печати научную статью или книгу.

Справочный материал

Часто встречающиеся математические функции в библиотеках math, NumPy и Sympy

Функция
math.
numpy.
sympy.
ex
exp(x)
exp(x)
exp(x)
ln(x)
log(x)
log(x)
log(x)
sqrt(x)
sqrt(x)
sqrt(x)
sin(x)
sin(x)
sin(x)
sin(x)
cos(x)
cos(x)
cos(x)
cos(x)
tg(x)
tan(x)
tan(x)
tan(x)
arcsin(x)
asin(x)
arcsin(x)
asin(x)
arccos(x)
acos(x)
arccos(x)
acos(x)
arctg(x)
atan(x)
arctan(x)
atan(x)
sh(x)
sinh(x)
sinh(x)
sinh(x)
ch(x)
cosh(x)
cosh(x)
cosh(x)
th(x)
tanh(x)
tanh(x)
tanh(x)

Цвет

Самый простой способ задания цвета в Matplotlib - с помощью одиночного символа. Правда, вариантов цветов в таком случае получается немного:

Тем не менее, на практике зачастую этого набора вполне хватает.

Другая возможность задания цвета в Matplotlib - с помощью строки, описывающей цвет полным английским словом. Таких именованных цветов намного больше, чем односимвольных. В документации есть хороший пример, генерирующий таблицу со всеми существующими именованными цветами. Она приведена ниже.

Стиль линии

Стиль линии также можно определять одиночным символом:

Символ
Линия
-
--
-.
:

Стиль маркера


Формулы в формате TeX

TeX (или LaTeX) - это система, позволяющая программировать верстку книг и научных статей, созданная Дональдом Кнутом, - одним из крупнейших в мире ученых в области информатики, написавшим культовую книгу "Искусство программирования". TeX появился в далеком 1978 г. (!) и до сих пор не потерял своих позиций в мире математиков и физиков. Свободные дистрибутивы этой издательской системы существуют и под Windows, и под Linux. Она не проста для усвоения, но позволяет создавать очень красивые (с точки зрения полиграфии) тексты. Matplotlib поддерживает систему обозначения математических формул, принятую в LaTeX. [Благодаря своему удобству эта система записи формул стала практически стандартом: она используется в Википедии, в редакторе формул LibreOffice и еще много где.] То есть дистрибутив LaTeX устанавливать не нужно, все заработает сразу.

Чтобы указать Matplotlib, что текстовая строка содержит формулу, достаточно эту формулу заключить в знаки $. Допустим, мы хотим, чтобы в легенде наш график обозначался формулой f(x)=sin(x)/x. Для этого достаточно параметру label функции plot, определяющей наш график, присвоить значение "$f(x)=\\frac{sin(x)}{x}$". Двойная обратная косая черта "\\" в TeX означает начало команды. Если нужно, чтобы в формуле появился кириллический символ, перед ней нужно поставить букву u, например так: u"$f(x)=\\frac{sin(x_{рю})}{x_{рю}}$".

Степени и индексы

Степени и индексы набираются с помощью знаков ^ и _ соответственно. Если показатель степени или индекс являются выражением, состоящим более чем из одного символа, то их надо заключать в фигурные скобки { и }. Например, следующие выражения преобразуются в формулы:

a^2+b^2=c^2         

a_2+b_2=c_2         

a^{b^{c}}             

Если у одной буквы есть как верхние, так и нижние индексы, то их можно указать в произвольном порядке:

a_{10}^{20}         

a^2_3                 

Если требуется, чтобы индексы располагались не один под другим, а на разных расстояниях от выражения, к которому они относятся, то нужно оформить часть индексов как индексы к "пустой" формуле (паре из открывающей и закрывающей фигурных скобок):

R_j{}^i{}_{kl}         

Дроби

Дроби, обозначаемые косой чертой, набираются непосредственно:

x+1/x    дает   

Дроби, в которых числитель расположен над знаменателем, набираются с помощью команды \\frac{числитель}{знаменатель}:

\\frac{(a+b)^2}{4}-\\frac{(a-b)^2}{4}=ab         

Скобки

Круглые и квадратные скобки набираются непосредственно. Для набора фигурных скобок используются команды \\{ и \\}. Например:

f\\{x,y\\}=(x^2+y^2)^2         

Другие типы скобок набираются с помощью команд \\lceil, \\rceil, \\lfloor, \\rfloor, \\langle, \\rangle. Например:

\\lceil X \\rceil, \\lfloor Y \\rfloor, \\langle Z \\rangle     

Для автоматического выбора размера скобок используются команды \\left и \\right, помещаемые перед открывающей и перед закрывающей скобками соответственно. Сравните:

(x+\\frac{1}{x})^2         

и

\\left( x + \\frac{1}{x} \\right)^2     

Корни

Корни набираются с помощью команды \\sqrt[n]{выражение}, обязательным аргументом которой является подкоренное выражение. Кроме обязательного аргумента можно указать необязательный аргумент, заключаемый в квадратные скобки, который является показателем корня.

\\sqrt{x+1}       

\\sqrt[3]{x+1}   

Интегралы и дифференциалы

В этом разделе собраны символы, наиболее часто используемые в дифференциальном и интегральном исчислении.

\\int           интеграл
\\iint          двойной интеграл
\\iiint         тройной интеграл
\\oint         круговой интеграл
\\partial     частная производная
\\infty        бесконечность
\\lim          предел
\\to           стрелка (в пределах)

Примеры использования:

\\int_{0}^{3}f(x)dx         

\\iint_{x^2+y^2=1}f(x,y)dxdy          (в Matplotlib отображается некорректно, как нижний индекс при знаке интеграла)

\\iiint_{x^2+y^2+z^2=1}f(x,y,z)dxdydz    (в Matplotlib отображается некорректно, как нижний индекс при знаке интеграла)

Неравенства

Строгие неравенства набираются непосредственно: a < b, a > b
Для нестрогих неравенств используются команды \\leq и \\geq:

,

Греческие буквы

Имя команды, задающей греческую букву совпадает с английским названием этой буквы. Исключение составляет буква "o" (омикрон), она совпадает с латинской буквой "o", поэтому специальной команды для нее не предусмотрено. Кроме того, некоторые греческие буквы имеют по два варианта написания, что также отражено в таблице. Только не забудьте вместо одиночной обратной косой черты ставить двойную!

Большинство прописных греческих букв совпадает по начертанию с латинскими буквами, поэтому специальных команд для них не предусмотрено - надо просто использовать соответствующую латинскую букву. Приведем перечень прописных греческих букв, не совпадающих с латинскими:

\\Gamma, \\Delta, \\Theta, \\Lambda, \\Xi, \\Pi, \\Sigma, \\Upsilon, \\Phi, \\Psi, \\Omega

Крышки, подчеркивания и т.д.

Команды для создания крышек, подчеркиваний и других подобных знаков имеют вид \\<имя>{выражение}, где <имя> - имя команды. Вот они:

\\hat{A} \\check{A} \\breve{A} \\acute{A} \\grave{A}
\\tilde{A} \\bar{A} \\vec{A} \\dot{A} \\ddot{A}


Можно использовать также следующие команды:

\\widetilde{ABC} \\widehat{ABC} \\overline{ABC}
\\overbrace{ABC} \\underbrace{ABC} \\underline{ABC}


Повторное использование кода или Как не изобрести квадратное колесо

С педагогической точки зрения использование в учебном процессе уже готовых решений может показаться неправильным. Действительно, самостоятельное решение задач по программированию "с нуля" выглядит очень привлекательной идеей. Так были созданы Unix, Linux и многие другие великие программы. Но по словам академика РАН, ректора Сколтеха Александра Кулешова, инженерия 70-х и нынешняя инженерия не имеют вообще ничего общего:

"большую часть своего времени специалист посвящает, условно говоря, рысканью по каталогу накопленных знаний. Даже в самых высокотехнологичных компаниях мира - Airbus и Boeing, где очень сильные сотрудники, рядовой инженер тратит 60% времени на поиск аналога того решения, которое ему необходимо. То есть сидит в интернете и ищет там какую-то готовую модель, которую потом ему надо будет подправить" [Юлаев А. "Мы снова оказались в 1929 году..." / znak.com.- 28 июня 2016 г.].

Еще одна пространная цитата:

"Нежелание выполнять ненужную работу считается великой добродетелью у программистов. Если бы китайский мудрец Лао-Цзы в наши дни все еще продолжал проповедовать учение Тао, то, возможно, его высказывание ошибочно переводили бы так: когда великий программист воздерживается от кодирования, то его сила чувствуется за тысячу миль. Действительно, современные переводчики предположили, что китайское понятие ву-вей, которое обычно передавалось словами "бездействие" или "воздержание от действия", вероятно, должно читаться как "наименьшее действие" или "наиболее эффективное действие", или как "действие в соответствии с естественным правом", что даже лучше описывает хорошую инженерную практику.

Следует помнить правило экономии. Повторные "поиски огня" и "изобретение колеса" для каждого нового проекта крайне расточительны. Время мышления дорого и весьма ценно по сравнению со всеми остальными производственными затратами при разработке программного обеспечения. Соответственно, его следует тратить на разрешение новых проблем, а не на переформулировку старых, для которых уже существуют известные решения. Такая позиция приносит наилучшую отдачу, как в понятиях интеллектуального капитала, так и в понятиях экономической эффективности инвестиций.

Изобретать заново колесо плохо не только потому, что при этом впустую тратится время, но и потому, что при этом часто создаются квадратные колеса. Существует почти непреодолимый сооблазн сэкономить на времени переизобретения, используя сырую и слабо продуманную версию, а это в долгосрочной перспективе часто оказывается ложной экономией (Генри Спенсер).

Наиболее эффективный способ избежать изобретения колеса заключается в заимствовании имеющейся конструкции и реализации, иными словами, в повторном использовании кода" [Реймонд Э.С. Искусство программирования для Unix.- М.: Издательский дом "Вильямс", 2005.- 544 с.].

3. Дифференцирование и интегрирование функций

Численное дифференцирование и интегрирование: библиотека NumPy/SciPy

Дифференцирование и интегрирование - далеко не самые простые для понимания понятия высшей математики. Причем, эти операции вводятся на базе теории пределов с использованием бесконечно большой и бесконечно малой величин, что еще больше "добавляет туману". Для нас производные и интегралы неразрывно связаны с аналитическими формулами, но большую часть функций из реального мира не удается выразить с помощью формул. Студенты вузов сначала изучают дифференцирование и интегрирование аналитических функций, но это просто так сложилось исторически.

Гораздо более универсальными (и простыми для понимания) являются дискретные производные и интегралы. Рассмотрим элементарный пример. Возьмем некоторую функцию, пусть для простоты это будет квадратная парабола y=f(x)=x2, и разделим ее на малые одинаковые участки по оси x. Теперь заменим непрерывную линию y=f(x) значениями этой функции на границах между участками, то есть вместо линии будем работать с набором точек. Такую замену называют дискретизацией. Непрерывность функции - это на самом деле лишь математическая абстракция. В реальной жизни любой процесс - дискретный, если не сам по себе, то хотя бы с точки зрения измерительных приборов.

Итак, задаваемая формулой функция - это непрерывное множество точек, образующих сплошную линию, а дискретная функция - это последовательность участочков неопределенно-малой длины, задаваемых координатами - значениями функции - концов участочков. Не всякую функцию можно описать математической формулой, но любую функцию можно заменить ее дискретным аналогом.

Что находится между точками-узлами дискретной функции? Точно мы не знаем, информации об этом у нас нет. Можно строить разные предположения, основываясь на значениях дискретной функции в узлах, например можно соединить узловые точки прямой линией. Такие предположения называют интерполяцией.

Что же такое производная дискретной функции? Положим, что длина всех участков по оси x одинакова и равна единице (такую систему единиц измерения подобрать можно всегда). Тогда для первого участка от точки 0 до точки 1 производная будет равна y'=Δy/Δx=(y(1)-y(0))/1=(1-0)/1=1. Это значение производной относится ко всему участку между точками x=0 и x=1. Аналогично для второго участка от 1 до 2: y'=Δy/Δx=(y(2)-y(1))/1=(4-1)/1=3. И для третьего от 2 до 3: y'=Δy/Δx=(y(3)-y(2))/1=(9-4)/1=5. Если нарисовать график дискретной производной, он будет выглядеть примерно как на рис.3.1.

Рис.3.1. Дискретная производная

Теперь покажем, как связаны друг с другом дискретные функции и их непрерывные аналоги. Вместо постоянного значения производной на каждом отдельном участке поставим одну точку с тем же значением посередине соответствующего участка (рис.3.2). Наложим на рисунок графики непрерывной функции y=x2 и ее непрерывной производной y'=2x: они пройдут в точности через точки их дискретных аналогов.

Рис.3.2. Связь дискретной и аналитической производных

Итак, все довольно просто и ясно. Дискретная производная несет в себе по сути ту же информацию, что и сама дискретная функция. Зная значение функции в начальной точке и имея график дискретной производной, можно легко восстановить первоначальную функцию. Такая операция называется интегрированием.

Почему же этим довольно примитивным операциям уделяется столь много внимания, что им посвящены отдельные разделы высшей математики - дифференциальное и интегральное исчисления? Все дело в том, что законы природы нашего мира представляют собой математические соотношения, состоящие из производных и интегралов. Изменение одних величин (скажем, потенциальной энергии свободно падающего предмета над поверхностью земли), рассчитанных по определенным формулам (Ep=mgh), равно изменению других величин (допустим, кинетической энергии того же свободно падающего предмета), тоже рассчитанных по определенным формулам (Ek=mv2/2). Это закон сохранения энергии, который лежит в основании большинства дифференциальных уравнений физики. А производные как раз и суть изменения тех или иных параметров.

Цель работы

В этой работе вам нужно будет найти численную производную и численный интеграл от заданной функции. В принципе, обе эти операции нетрудно запрограммировать самому. Нахождение определенного интеграла по методу трапеций или по методу Симпсона - стандартная задачка по программированию. Написать процедуру для нахождения численной производной - еще проще. Тем не менее, для численного дифференцирования и интегрирования мы воспользуемся уже готовыми функциями из библиотеки NumPy/SciPy. Эта Python-библиотека поддерживает работу с многомерными массивами, в ней реализованы многие алгоритмы из линейной алгебры, преобразование Фурье, генератор случайных чисел и т.п. Наконец, она довольно быстрая - не уступает по скорости, скажем, аналогичным функциям коммерческого пакета MATLAB.

Примеры

Вот как можно численно продифференцировать заданную функцию y=x2 и построить графики самой функции и ее производной, найденной численно и аналитически:

# -*- coding: UTF-8 -*-

# Импортируем стандартную, "внутреннюю" библиотеку math
import math

# Импортируем из SciPy функцию для численного определения
# производной derivative
from scipy.misc import derivative

# Импортируем один из пакетов Matplotlib
import pylab

# Импортируем пакет со вспомогательными функциями
from matplotlib import mlab


# Заданная функция (y=x*x)
def func(x):
    return x**2.

# Производная заданной функции, найденная аналитически, точно
def func_diff(x):
    return 2.*x

# Диапазон изменения переменной по оси X
xmin=-20.0
xmax=20.0

# Шаг между точками
dx=1.

# Создадим список координат по оси X на отрезке [-xmin; xmax],
# включая концы
xlist=mlab.frange(xmin, xmax, dx)

# Вычислим значения функции во всех заданных точках
ylist=[func(x) for x in xlist]

# Вычисляем производную численно во всех заданных точках
ylist2=[derivative(func, x, dx=1e-6) for x in xlist]

# Вычисляем точное значение производной во всех заданных точках
ylist3=[func_diff(x) for x in xlist]

# Рисуем график самой функции и ее производной, полученной численно
pylab.plot(xlist, ylist, 'b', label="y=$x^2$")
pylab.plot(xlist, ylist2, 'r.', label="""y'=$\\Delta y/\\Delta x$""")

# Рисуем график производной, найденной аналитически
pylab.plot(xlist, ylist3, 'r', label="""y'=2x""")

# Обозначаем координатные оси
pylab.xlabel('X',fontsize=16)
pylab.ylabel('Y',fontsize=16)

# Регулируем размер числовых отметок на координатных осях
pylab.xticks(fontsize=12)
pylab.yticks(fontsize=12)

# Рисуем координатную сетку
pylab.grid()

# Выводим легенду
pylab.legend(fontsize=12)

# Показываем окно с нарисованными графиками
pylab.show()

Рис.3.3. График функции y=x2 и ее производной, найденной численно и аналитически

Аналогичный пример численного интегрирования заданной функции и сравнение полученного результата с известным аналитическим решением:

# -*- coding: UTF-8 -*-

# Импортируем стандартную, "внутреннюю" библиотеку math
import math

# Импортируем из SciPy функцию для численного интегрирования
import scipy.integrate as integrate

# Импортируем один из пакетов Matplotlib
import pylab

# Импортируем пакет со вспомогательными функциями
from matplotlib import mlab


# Заданная функция (y=2x)
def func(x):
    return 2.*x

# Значение интеграла, найденного аналитически, точно
def func_integr(x):
    return x**2.

# Диапазон изменения переменной по оси X
xmin=-20.0
xmax=20.0

# Шаг между точками
dx=1.

# Создадим список координат по оси X на отрезке [-xmin; xmax],
# включая концы
xlist=mlab.frange(xmin, xmax, dx)

# Вычислим значения функции во всех заданных точках
ylist=[func(x) for x in xlist]

# Вычисляем интеграл от заданной функции численно во всех заданных точках
ylist2=[integrate.quad(func, 0.0, x)[0] for x in xlist]

# Вычисляем интеграл от заданной функции аналитически во всех заданных точках
ylist3=[func_integr(x) for x in xlist]

# Раскомментируйте следующую строку. Что выводится функцией integrate.quad
# в командную строку?
#print integrate.quad(func, 0.0, 3.)

# Рисуем график самой функции и интеграла от нее, полученного численно
pylab.plot(xlist, ylist, 'b', label="y'=2x")
pylab.plot(xlist, ylist2, 'r.', label="y=$\\int (2x)dx$")

# Рисуем график интеграла, найденного аналитически
pylab.plot(xlist, ylist3, 'r', label="y=$x^2$")

# Обозначаем координатные оси
pylab.xlabel('X',fontsize=16)
pylab.ylabel('Y',fontsize=16)

# Регулируем размер числовых отметок на координатных осях
pylab.xticks(fontsize=12)
pylab.yticks(fontsize=12)

# Рисуем координатную сетку
pylab.grid()

# Выводим легенду
pylab.legend(fontsize=12)

# Показываем окно с нарисованными графиками
pylab.show()

Рис.3.4. График функции y=2x и интеграла от нее, найденного численно и аналитически

Воспользовавшись "лупой" с панели инструментов окна Matplotlib, нетрудно убедиться, что определенные с помощью численных процедур значения производной и интеграла очень точно ложатся на графики, соответствующие аналитическим решениям.

Задание

Пользуясь шаблонами, построить графики численной производной и численного интеграла от заданной функции (свободный член во всех формулах опущен):


  1. Для этой и последующих функций шаг dx надо взять поменьше - скажем, 0.1 вместо 1. Иначе будет "потеряна" форма функции.
Ясно, что производная от правой части каждого уравнения равна подынтегральному выражению.

Сравнить полученные численные решения с точными. Указать в легенде свою исходную функцию и результат в формате TeX.

В заключение давайте немного "пошумим" - наложим на функцию func(x) случайный "белый" шум и снова ее численно продифференцируем и проинтегрируем. Для этого в начало каждого примера надо добавить строку:

import numpy as np

и модифицировать определение функции func(x):

return x**2.+0.0001*np.random.uniform(0.,1.)

Функция np.random.uniform(0.,1.) генерирует псевдослучайные числа в диапазоне от 0 до 1, а множитель 0.0001 определяет среднюю амплитуду случайных отклонений от идеального аналитического графика. Поэкспериментируйте с величиной этого множителя, увеличивая и уменьшая его порядок (0.001, 0.01, 0.1, 0.00001 и т.п.) и в случае дифференцирования, и в случае интегрирования. Обратите внимание, как будет меняться график численной производной и численного интеграла в зависимости от величины этого множителя.

Вопросы

  1. Почему при интегрировании в некоторых случаях численное и аналитическое решение могут быть смещены относительно друг друга по оси Y?

  2. Какая из операций - дифференцирование или интегрирование - более чувствительна к случайному шуму? Как вы думаете, почему?

Литература

  1. Массивы в scipy (numpy), шпаргалка (Колдунов Н.)
    Перевод шпаргалки по массивам в SciPy.
  2. Ivan Idris. NumPy Beginner's Guide. Birmingham-Mumbai: PACKT Publishing, 2013.- 287 p.
    Руководство по NumPy для начинающих.

Математическая бесконечность как вычислительный прием

Странный это был отдел. Лозунг у них был такой:
"Познание бесконечности требует бесконечного времени"
(бр.Стругацкие. Понедельник начинается в субботу).

Понятие бесконечности я помню с детства, и уже тогда оно производило ошеломляющее впечатление:

"Вселенная, весь мир, безграничный во времени и пространстве и бесконечно разнообразный по тем формам, которые принимает материя в процессе своего развития... Вселенная содержит гигантское множество небесных тел, многие из которых по размерам превосходят Землю иногда во много миллионов раз... Ограниченность изученной части Вселенной никоим образом не противоречит идее о пространственной бесконечности Вселенной" (Большая советская энциклопедия, ст."Вселенная").

Позже с ним пришлось встретиться в институте при изучении теории пределов, дифференциального и интегрального исчислений. Там, оно применялось буквально сплошь и рядом. Но интеллектуальный дискомфорт, связанный с этим понятием, никуда не исчез. С одной стороны, математическая бесконечность стала привычной; как и все, я научился с ее помощью решать задачи. С другой стороны, человеческий разум явно не справлялся при попытках философски ее осмыслить.

Попробуем разобраться.

Проще всего понять, какую роль играет математическая бесконечность, на примере физических задач. Зададимся вопросом: какое крыло проще изучать с математической точки зрения - бесконечного размаха или конечного? Конечно же, бесконечного. Тогда эту задачу можно свести к плоскопараллельному движению и рассматривать единый для всего крыла профиль. В такой постановке проблема допускает теоретическое исследование, и на самом деле на ее базе были получены такие важные результаты, как, скажем, теорема о подъемной силе Кутта-Жуковского. Крыло же конечного размаха подразумевает трехмерное течение, что очень сильно осложняет дело. Таким образом, в данном случае и во многих других "бесконечность" означает всего-навсего отбрасывание (приравнивание нулю) некоторых частей физической картины с целью упрощения постановки задачи.

Это, конечно же, не случайно. Как известно из теории пределов, если функция f(x) - бесконечно большая величина, то 1/f(x) - бесконечно малая величина или попросту ноль. То есть математическая бесконечность - это по сути ноль, только стоящий в знаменателе дроби. А уж, что такое ноль, можно понять и представить без всякой философии.

В связи с этим интересен случай, рассказанный В.И.Арнольдом [Арнольд В.И. Что такое математика?- М.: МЦНМО, 2002.- 104 с.]:

"Когда Я.Б.Зельдович, замечательный физик-теоретик и один из основателей российской ядерной мощи, выпустил в свет свою "Высшую математику для начинающих физиков и техников", она вызвала страшный гнев тогдашнего цензора математической литературы, академика-математика Л.С.Понтрягина.

Он справедливо указал, что Зельдович определял в своей книге производную функции как "величину отношения приращения функции к приращению аргумента, в предположении, что последнее мало".

Математик был возмущен полным исключением здесь понятий теории пределов, а тем самым и значительной части логического обоснования математического анализа, достигшего совершенства лишь к концу девятнадцатого века, с созданием последовательной теории математического континуума действительных чисел.

Зельдович ответил так: интересует нас всегда именно отношение конечных приращений, а вовсе не какой-то абстрактно-математический предел.

Делать приращение аргумента - скажем, координаты точки или момента времени - меньшим, чем, скажем, 10-10 или 10-30 (при разумных единицах измерения),- это "явное превышение точности модели, так как структура физического пространства (или времени) на столь малых интервалах уже вовсе не соответствует математической модели теории вещественных чисел (вследствие квантовых феноменов)".

"Дело,- продолжал Зельдович,- просто в том, что находить интересующие нас отношения конечных приращений трудно, поэтому и придуманы приближенные асимптотические формулы для них. Эти-то приближенные формулы математики и называют своими пределами и математическими производными. В любом реальном применении теории следует учитывать, меньше чего не следует делать приращения, чтобы результаты теории соответствовали эксперименту"".

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

"Такой крупнейший французский философ, как Рене Декарт (1596-1650), утверждал, что представление о бесконечности каких-либо объектов материального мира "проистекает из недостаточности нашего разума, а не из природы". Тем самым Декарт хотел сказать, что никакой реальной бесконечности в мире не существует, она - продукт несовершенства человеческого мышления. При этом вовсе не случайно Декарт называет бесконечность мира неопределенностью, превращая ее в своеобразный символ неспособности человека охватить своим разумом окружающий мир, представить себе его границы" [Комаров В.Н. По следам бесконечности. М.: Знание, 1974.- 192 с.].

"На свете не мало вещей ограниченных и так или иначе несовершенных, хотя бы мы и отмечали в них известные совершенства... Итак, если Бог по Своей милости открывает нам или кому-либо другому нечто такое, что превосходит естественные пределы нашего понимания, например, таинства воплощения и троичности, то мы не затруднимся верить в них, хотя бы не постигали их ясно, ибо мы не должны удивляться, что как в неизмеримой природе Бога, так и в созданных Им вещах существует многое, превосходящее меру нашего понимания.

Таким образом, мы никогда не станем вступать в споры о бесконечном, тем более что нелепо было бы нам, существам конечным, пытаться определить что-либо относительно бесконечного и полагать ему границы, стараясь постичь его. Вот почему мы не сочтем нужным отвечать тому, кто спрашивает, бесконечна ли половина бесконечной линии, или бесконечное число четное или нечетное и т.п. О подобных затруднениях, повидимому, не следует размышлять никому, кроме тех, кто считает свой ум бесконечным. Мы же относительно того, чему в известном смысле не видим пределов, границ, не станем утверждать, что эти границы бесконечны, но будем лишь считать их неопределенными. Так, не будучи в состоянии вообразить столь обширного протяжения, чтобы в то же самое время не мыслить возможности еще большего, мы скажем, что размеры возможных вещей неопределенны. А так как никакое тело нельзя разделить на столь малые части, чтобы каждая из них не могла быть разделена на еще мельчайшие, то мы станем полагать, что количество делимо на части, число которых неопределенно. И так как невозможно представить столько звезд, чтобы Бог не мог создать их еще больше, то их число мы предположим неопределенным. То же относится и ко всему остальному.

Все это мы скорее назовем неопределенным, а не бесконечным или беспредельным, чтобы название "бесконечный" сохранить для одного Бога, столь же потому, что в Нем одном мы не видим никаких пределов Его совершенствам, сколь и потому, что знаем твердо, что их не может быть. Что же касается остальных вещей, то мы знаем, что они несовершенны, ибо, хотя мы и отмечаем в них подчас свойства, кажущиеся нам беспредельными, мы не можем не знать, что это проистекает из недостаточности нашего разума, а не из их природы." [Декарт Р. Избранные произведения. М.: Государственное издательство политической литературы, 1950.- С.436-438.]

На мой взгляд, предложенное Декартом название - "неопределенно малая величина" - гораздо лучше отражает суть вещей по сравнению с используемым сегодня повсеместно термином "бесконечно малая величина". Такую бесконечность уместно назвать потенциальной. Например, во втором постулате Евклида утверждается возможность продолжить бесконечно и непрерывно любую прямую. Таким образом, ограничений для продолжения этого процесса нет, но это не значит, что в реальном мире может существовать такой объект, как прямая бесконечной длины. Фактическую, физическую бесконечность (скажем, реальное тело бесконечных размеров) называют актуальной. Если бы физикам удалось доказать, что Вселенная бесконечна, она была бы примером актуальной бесконечности.

Фактически, описание бесконечности в математике (для каждого сколь угодно большого числа можно указать другое число, большее его) лишь констатирует ограниченность человеческого знания: сколько бы мы ни узнали, непознанного всегда будет больше.

Более подробно о понятии бесконечности и пределах познания рассказывается в моей статье "Границы науки".

Символьные вычисления на Python: библиотека SymPy

Символьные вычисления - воплощенная мечта школьников и студентов о роботе, решающем вместо них домашние задания по математике. SymPy - это на самом деле такой робот, но для плодотворной работы с этой системой нужно хорошо понимать, что она делает, то есть самому уметь производить вручную все эти операции сложения обыкновенных дробей, преобразования тригонометрических функций, аналитического дифференцирования и тому подобное.

В отличие от популярных коммерческих систем компьютерной алгебры - Mathematica, Mathcad, Maple, лицензии на которые стоят сотни долларов США, SymPy совершенно бесплатна (лицензия BSD). Ее код можно свободно модифицировать и даже продавать, если хотите.

Вторая важная особенность SymPy - это язык программирования. Как правило, для каждой системы компьютерной математики разрабатывается свой язык. SymPy полностью написана на Python и исполняется полностью в среде Python. Есть еще одна свободная система для символьных вычислений, использующая Python,- это Sage. Кстати, SymPy входит в Sage. Но Sage - очень громоздкий пакет, его дистрибутив "весит" свыше гигабайта.

SymPy входит в базовый комплект пакетов дистрибутива Anaconda, так что отдельной установки для него не потребуется. На мой вкус SymPy, как и Python в целом, идеально подходит на роль стандартного программного продукта для использования в сфере среднего и высшего образования. Да, SymPy скорее всего не конкурент коммерческим системам, когда речь идет о профессиональной математике или о применении в промышленности. Но для школы, вуза, аспирантуры его возможностей хватит с избытком.

Как и в предыдущих разделах, знакомство с символьными вычислениями и возможностями SymPy начется с окна командной строки Idle. Допустим, что нам нужно найти квадратный корень из 8. Вызываем внутреннюю библиотеку Python math и проводим вычисления:

>>> import math
>>> math.sqrt(8)
2.8284271247461903
>>>

Очевидно, что 2.8284271247461903 - это не точное значение квадратного корня из 8. Фактически, точно это число вообще не может быть найдено, потому что оно иррациональное. Если все, что нам нужно, - это приближенное десятичное значение, то здесь можно остановиться.

Теперь, вспомнив, что , попробуем поработать непосредственно с квадратным корнем из 8, задействовав библиотеку SymPy:

>>> import sympy
>>> sympy.sqrt(8)
2*sqrt(2)
>>>

Итак, системы символьных вычислений не извлекают квадратный корень из числа, если оно не является точным квадратом. Более того, SymPy смогла упростить обрабатываемое выражение. Это значит, что квадратный корень из восьми для нее не число (как это было бы для чистого Python), а некий символ, который система может преобразовывать по известным из математики правилам. Отсюда название - символьные вычисления.

Разумеется, SymPy может воспринимать как символы не только числа, такие как квадратный корень из 8, но и обычные переменные. Для этого сначала нужно явно определить их как особые символьные переменные:

>>> x=sympy.Symbol('x')
>>> y=sympy.Symbol('y')

>>> x+y+x-y
2*x

>>> (x+y)**2
(x+y)**2

>>> ((x+y)**2).expand()
x**2 + 2*x*y + y**2

Все действия, в том числе и функция expand(), интуитивно понятны. Обратите внимание, команды записаны так, будто x и y - обычные переменные Python. Но вместо того чтобы рассчитать какое-нибудь числовое значение, программа оставляет эти выражения как есть или преобразовывает их, скажем, раскрывая скобки.

Символ нижнего подчеркивания _ в SymPy и в целом в Python - это особая переменная, в которой содержится последнее выведенное на печать в командной строке выражение. Она очень удобна для работы в командной строке. Последние две команды можно было записать так:

>>> (x+y)**2
(x+y)**2

>>> _.expand()
x**2 + 2*x*y + y**2

Все возможности SymPy невозможно охватить в одном обзоре. Поэтому далее будут рассмотрены лишь те функции, которые нужны для выполнения задания этого раздела.

Любое выражение SymPy можно продифференцировать, используя sympy.diff(func,var):

>>> sympy.diff(sympy.sin(2*x), x)
2*cos(2*x)

>>> sympy.diff(sympy.tan(x), x)
tan(x)**2 + 1

Безусловно, можно выполнить импортирование сразу всех функций библиотеки SymPy с помощью команды:

>>> from sympy import *

Тогда предыдущие строки можно записать более компактно:

>>> diff(sin(2*x), x)
2*cos(2*x)

>>> diff(tan(x), x)
tan(x)**2 + 1

Но из методических соображений, особенно когда в программе используется еще и math и/или NumPy, чтобы всегда отдавать себе отчет в том, что и откуда берется, лучше записывать функции SymPy полностью вместе с названием библиотеки: обычные математические функции вроде sin(x) или log(x) присутствуют в разных библиотеках и даже могут называться по-разному (см. таблицу функций в разделе "Библиотека научной графики Matplotlib").

Привычное значение tg'(x)=1/cos2x легко получить, выполнив преобразование:

Аналогично работает и функция интегрирования:

>>> sympy.integrate(6*x**5, x)
x**6

>>> sympy.integrate(sympy.log(x), x)
x*log(x) - x

Для действий с обыкновенными, недесятичными дробями предусмотрен особый числовой тип Rational. Любую пару целых чисел он определяет как числитель и знаменатель, далее над дробями можно производить обычные действия: умножать, делить, складывать и так далее:

>>> sympy.Rational(1,2)+sympy.Rational(1,3)
5/6

Вообще нужно проявлять осторожность при использовании знака деления / для дробных выражений. Так совершенно нормальная на первый взгляд запись:

>>> (x**2/2+1/2)/(x**2+1)

неожиданно дает неправильный результат:

x**2/(2*(x**2 + 1))

вместо 1/2. В чем дело? Нельзя записывать обыкновенные дроби в виде 1/2, только sympy.Rational(1,2). Запись дроби в виде 1/2 Python трактует как деление двух целых чисел. Результатом такой операции будет 0.

Разложение квадрата двучлена с помощью функции expand() было показано выше. Обратное преобразование - выделение квадрата двучлена из квадратного трехчлена - реализуется с помощью функции factor():

>>> (x**2 + 2*x*y + y**2).factor()
(x + y)**2

или

>>> sympy.factor(x**2 + 2*x*y + y**2)
(x + y)**2

SymPy - хороший инструмент, но пользоваться им нужно с осторожностью. Попробуйте порешать с его помощью примеры из школьного учебника алгебры или "Сборника задач по курсу математического анализа" Бермана: далеко не все будет получаться как вы ожидаете или получаться вообще. Я бы сказал, что этот пакет не замена, а скорее полезное дополнение к "ручным" аналитическим вычислениям. С его помощью можно (и нужно!) проверять громоздкие выкладки, сделанные вручную на листке бумаги. Но к аналитическим решениям, получаемым автоматически, нужно относиться со здоровым скепсисом, проверяя их с помощью приближенных численных методов и обязательно строя графики! Благо, соответствующие инструменты среди библиотек Python есть и ими нетрудно пользоваться.


Лицензия Creative Commons
Это произведение доступно по лицензии Creative Commons «Attribution-ShareAlike» («Атрибуция — На тех же условиях») 4.0 Всемирная.

О замеченных ошибках, неточностях, опечатках просьба сообщать по электронному адресу:
russianlutheran@gmail.com