- •Формальные языки записи алгоритмов
- •Трансляторы и интерпретаторы языков программирования
- •Зачем нужно уметь программировать?
- •Комментарии к коду
- •Комментарии к коду
- •Экзотические языки программирования Специальные, экзотические и эзотерические языки программирования
- •Эзотерические языки программирования
- •О языке Python
- •Рекомендуемая литература
- •Интерпретация и компиляция
- •Алгоритм работы простого интерпретатора:
- •Ввод-вывод в Python Ввод данных
- •Вывод данных
- •Установка Python и сред разработки
- •Установка интерпретатора
- •Установка интегрированной среды разработки
- •Cреда программирования wing ide
- •Ключевые слова и идентификаторы в Python Идентификаторы
- •Ключевые слова
- •Концепция присваивания
- •Функция определения длины строки в Python
- •Литералы строк в Python
- •Срезы строк в Python
- •Примеры срезов
- •Методы строк в Python
- •Методы find и rfind
- •Метод replace
- •Метод count
- •Работа с тестирующей системой
- •Задачи поиска, замены и удаления подстроки в строке в Python
- •Метод replace
- •Метод count
- •Удаление подстроки
- •Числа с плавающей точкой (вещественные)
- •Основные операции с вещественными числами
- •Логический тип (bool) в Python
- •Логические операции
- •Принцип условного исполнения
- •Условная инструкция в Python
- •Вложенные условные инструкции
- •Операторы сравнения
- •Логические операторы
- •Каскадные условные инструкции
- •Инструкция pass в Python
- •Инструкции управления циклом в Python
- •Цикл while в Python
- •Вывод числа с обратным порядком цифр и в заданной системе счисления
- •Тест простоты
- •Проверка простоты перебором делителей
- •Факторизация перебором делителей
- •Факторизация перебором делителей на python
- •Факторизация перебором делителей на pascal
- •Разложение числа на множители в Python
- •Алгоритм Евклида: Python
- •Проверка числа на простоту в Python
- •Функция range
- •Фильтрация потока чисел
- •Поиск числа в потоке на Python
- •Поиск максимального и минимального числа в потоке на Python
- •Генерация псевдослучайных чисел
- •Детерминированные генераторы
- •Обработка исключений
- •Генерация исключений
- •"Страхование" от ошибок
- •Функции в программировании
- •Важное дополнение
- •Как написать хорошую функцию
- •Преимущества структурного программирования
- •Без использования структурного программирования
- •С использованием структурного программирования
- •Задания
- •Данная программа ищет самый популярный фильм среди данных
- •Функции в Python
- •Вызов функции и возврат значения
- •Передача параметров в функцию
- •Примеры
- •Граф вызовов функций
- •Пример на языке си
- •Что вернет функция a() в место своего вызова?
- •В каком порядке будут напечатаны X() started и X() finished для a, b, c, d?
- •Стек вызовов
- •Области видимости переменных в Python
- •Правила видимости имен
- •Пример перекрытия областей видимости
- •Доступ на присваивание к нелокальным именам
- •Полиморфизм функций в Python
- •Контрольные вопросы
- •Решение
- •Решение
- •Математические функции в Python
- •Функции в библиотеке math
- •Степенные и логарифмические функции
- •Тригонометрические функции
- •Радианы в градусы и наоборот
- •Пример программы с математическими функциями
- •Кортежи в Python Кортежи в Python
- •Кортежи в логическом контексте
- •Присваивание нескольких значений за раз
- •Методы split и join для списка строк в Python
- •Списки в Python
- •Сортировка выбором
- •Пример сортировки выбором минимума на си
- •Пример сортировки выбором минимума на python
- •Пример сортировки выбором минимума на pascal
- •Сортировка методом пузырька
- •Реализация сортировки массива методом пузырька на языке python
- •Реализация сортировки массива методом пузырька на языке pascal
- •Модернизация сортировки методом пузырька
- •Случайное перемешивание массива в Python
- •Сортировка подсчетом
- •Пример сортировки подсчетом на python
- •Пример сортировки подсчетом на языке си
- •Пример сортировки подсчетом на языке pascal
- •Генерация псевдослучайных чисел
- •Детерминированные генераторы
- •Вычисление суммы натуральных чисел от 1 до n
- •Проверка строки на палиндромность
- •Суммирование списка
- •Наибольшее значение в списке
- •Числа фибоначчи
- •Быстрое возведение в степень
- •Ханойские башни
- •Ограничение на глубину рекурсии
- •Стиль программирования (для Python)
- •Основные правила pep 8: Форматирование
- •Комментарии
- •Функции
- •Работа с текстовыми файлами в Python открытие файла
- •Чтение данных из файла
- •Вывод данных в файл
- •Закрытие файла
- •Двумерные массивы в Python
- •Создание вложенных списков
- •Ввод двумерного массива
- •Пример обработки двумерного массива
- •Вложенные генераторы двумерных массивов
- •Генераторы таблиц
- •Вычисление произведения матриц
- •Многомерные списки в Python обработка и вывод вложенных списков
- •Создание двумерного списка
- •Ввод двумерного списка
- •Сложный пример обработки двумерной таблицы
- •Множества в Python
- •Создание множества
- •Изменение множества
- •Удаление элементов множества
- •Основные операции с множествами
- •Множества в логическом контексте
- •Множества
- •Задание множеств
- •Работа с элементами множеств
- •Перебор элементов множества
- •Операции с множествами
- •Словари (ассоциативные массивы) в Python
- •Когда нужно использовать словари
- •Создание словаря
- •Работа с элементами словаря
- •Перебор элементов словаря
- •Словари со смешанными значениями
- •Пример хранения списков в словаре
- •Пример дешифрации текста после алфавитной замены
- •Дан текст:
- •Итог всех замен:
- •Итог всех замен:
- •Окончательный вариант:
- •Рекурсивный перебор
- •Перебор всех подмножеств
- •Перебор всех k-элементных подмножеств
- •Перебор всех перестановок
- •Одномерное динамическое программирование: количество способов Задача о кузнечике
- •Рекурсивное решение
- •Пример на языке python
- •Пример на языке pascal
- •Нерекурсивное решение
- •Пример на языке python
- •Пример на языке pascal
- •Модификации задачи о кузнечике
- •Пример на языке python
- •Пример на языке pascal
- •Пример на языке python
- •Пример на языке pascal
- •Одномерное динамическое программирование: наилучший способ задача о кузнечике со стоимостями
- •Пример на языке python
- •Пример на языке pascal
- •Восстановление ответа
- •Пример программы на языке python:
- •Пример программы на языке pascal:
- •Пример программы на языке python:
- •Пример программы на языке pascal:
- •Пример программы на языке python
- •Пример программы на языке pascal:
- •Линейные задачи
- •Рекурсивный перебор
- •Перебор всех подмножеств
- •Перебор всех k-элементных подмножеств
- •Перебор всех перестановок
- •Сортировка слиянием
- •Быстрая сортировка Хоара: Python
- •Асимптотика алгоритма
- •Объектно-ориентированное программирование
- •Классы в Python
- •Метод init
- •Создание экземпляров
- •Переменные экземпляра
- •Плановая обработка ошибок при помощи исключений в Python
- •Обработка исключений
- •Генерация исключений
- •“Страхование” от ошибок
- •Юнит-тестирование
- •Тестирование как этап разработки программы
- •Виджеты
- •Происхождение термина «виджет»
- •Типовые элементы интерфейса
- •Модуль tkinter Что такое tkinter?
- •Класс Tk
- •Общее для всех виджетов
- •Методы виджетов
- •"Системные" методы
- •Пример, часы:
- •Пример:
- •Основные виджеты
- •Методы виджета
- •Упаковщики
- •Привязка событий
- •Изображения
- •Пошаговые инструкции
- •Математические функции в Python
- •Функции в библиотеке math
- •Степенные и логарифмические функции
- •Тригонометрические функции
- •Радианы в градусы и наоборот
- •Пример программы с математическими функциями
- •Массивы чисел в модуле math Массивы чисел
- •Векторы
- •Математические операции над векторами
- •Векторные функции
- •Использование списков
- •Основы Numerical Python
- •К слову, о срезах
- •Задание координат и значений функций
- •Векторизация
- •Визуализация функций в Matplotlib
- •Набор точек
- •Функция
- •Украшения
- •Несколько кривых
- •Маркеры
- •Дополнительные аргументы plot()
- •Сохранение файла
- •Гистограммы
- •Модуль os в Python
- •Текущий рабочий каталог
- •Работа с именами файлов и каталогов
- •Получение содержимого каталога
- •Получение сведений о файле
- •Получение абсолютных путей
- •Анализ аргументов командной строки в Python
- •Примеры без использования argparse
- •Использование библиотеки argparse
Генерация псевдослучайных чисел
«Генерация случайных чисел слишком важна, чтобы оставлять её на волю случая» Роберт Р. Кавью
ОПРЕДЕЛЕНИЕ
Генерация псевдослучайных чисел — порождение последовательности чисел, элементы которой подчиняются заданному распределению (обычно равномерному).
Псевдослучайные числа используются в методе Монте-Карло, в криптографии, для моделирования физической и игровой реальности, для придания действиям игрового искусственного интеллекта элемента спонтанности.
Соответствующие алгоритмы называют генераторами псевдослучайных чисел (ГПСЧ).
Детерминированные генераторы
Детерминированный алгоритм не может генерировать полностью случайные числа, он может только аппроксимировать некоторые их свойства.
Любой ГПСЧ с ограниченными ресурсами рано или поздно зацикливается — начинает повторять одну и ту же последовательность чисел. Если порождаемая ГПСЧ последовательность сходится к слишком коротким циклам, то такой ГПСЧ становится предсказуемым и непригодным для практических приложений.
Большинство простых арифметических генераторов имеют недостатки:
Слишком короткий период.
Последовательные значения не являются независимыми.
Некоторые биты «менее случайны», чем другие.
Неравномерное одномерное распределение.
Обратимость.
Линейный конгруэнтный метод
Члены последовательности вычисляются рекуррентно по формуле:
Xk+1=(aXk+c)mod m
где a и c — некоторые целочисленные коэффициенты, а mod m — взятие остатка по модулю некоторого натурального числа m.
НОД(c,m)=1 (то есть, c и m взаимно просты);
a−1 кратно p для всех простых делителей p числа m;
a−1 кратно 4, если m кратно 4.
длина периода меньше либо равна m.
ЧАСТО ИСПОЛЬЗУЕМЫЕ ПАРАМЕТРЫ
m=232,a=69069,c=5
m=232,a=22695477,c=1
m=232,a=1664525,c=1013904223
m=264,a=6364136223846793005,c=1442695040888963407
Линейный конгруэнтный метод дает статистически приемлемое распределение псевдослучайных чисел, но не является криптостойким.
Реализация линейного конгруэнтного метода на Си
unsigned long g_random_seed = 1; //глобальная переменная с последним числом unsigned long my_rand() { //размер unsigned long равен 4 байта! //m = 2^32 return g_random_seed = 69069LU*g_random_seed + 5LU; }
Реализация линейного конгруэнтного метода на Python
g_random_seed = 1 def rr(): global g_random_seed g_random_seed = (69069*g_random_seed+5)%(2**32)
ВОПРОС
Почему в алгоритме на Си отсутствует деление по модулю m, но код работает, а в Python наличие %(2**32)обязательно?
ОТВЕТ
В языке Python реализована длинная арифметика, и целые числа могут быть произвольной длины, а в Си размер числа ограничен количеством бит, отведенных под него.
При этом unsigned long int имеет размер 4 байта — это 32 бита, следовательно результаты операций сложения и умножения в Си для типа unsigned long int и так всегда будут происходить по модулю 232.
Рекурсия в Python
Функции могут вызывать и другие функции, и даже вызывать сами себя! Рассмотрим это на примере функции вычисления факториала. Хорошо известно, что 0!=1, 1!=1. А как вычислить величину n! для большого n? Если бы мы могли вычислить величину (n−1)!, то тогда мы легко вычислим n!, поскольку n!=n(n−1)!. Но как вычислить (n−1)!? Если бы мы вычислили (n−2)!, то мы сможем вычисли и (n−1)!=(n−1)(n−2)!. А как вычислить (n−2)!? Если бы… В конце концов, мы дойдем до величины 0!, которая равна 1. Таким образом, для вычисления факториала мы можем использовать значение факториала для меньшего числа. Это можно сделать и в программе на Питоне:
def factorial(n): if n == 0: return 1 else: return n * factorial(n - 1)
Подобный прием (вызов функцией самой себя) называется рекурсией, а сама функция называетсярекурсивной.
Как это работает? Допустим, мы вызвали функцию factorial(4). Будет вызвана функция, у которой значение параметра n==4. Она проверит условие n==0, поскольку условие ложно, то будет выполнена инструкция return n∗factorial(n−1). Но чтобы вычислить это значение, будет вызвана функция factorial(3), т. к. параметр n имеет значение, равное 4. Теперь в памяти будет находиться две функции factorial — одна со значением параметра n==4, а другая — n==3. При этом активна будет последняя функция.
Эта функция в свою очередь вызовет функцию factorial(2), та вызовет функцию factorial(1), затем factorial(0). В случае этой функции ничего более вызвано не будет, функция просто вернет значение 1, и управление вернется в функцию factorial(1). Та умножит значение n==1 на значение 1, которое вернула функция factorial(0), и вернет полученное произведение, равное 1. Управление вернется в функцию factorial(2), которая умножит n==2 на значение 1, которое вернула функция factorial(1) и вернет полученное произведение, равное 2. Функция factorial(3) вернет 3∗2==6, а функция factorial(4) вернет 4∗6==24.
Таблица последовательности, в которой будут вызываться функции, приведена ниже. Значения функции возвращают в порядке, обратном порядке их вызова, то есть сначала заканчивает работу функция factorial(0), затем factorial(1) и т. д.
С какими параметрами вызвана функция |
Какое значение вернула |
factorial(4) |
4 * 6 == 24 |
factorial(3) |
3 * 2 == 6 |
factorial(2) |
2 * 1 == 2 |
factorial(1) |
1 * 1 == 1 |
factorial(0) |
1 |
При отладке программы всю последовательность вложенных вызовов рекуррентных функций можно изучить в окне «Call Stack» («стек вызовов») в режиме отладки среды Wing IDE. При этом значения локальных переменных будут отображаться в окне «Stack data», и для каждой вызываемой функции значения локальных переменных будут своими.
Для того, чтобы реализовать рекурсию нужно ответить на следующие вопросы:
Какой случай (для какого набора параметров) будет крайним (простым) и что функция возвращает в этом случае?
Как свести задачу для какого-то набора параметров (за исключением крайнего случая) к задаче, для другого набора параметров (как правило, с меньшими значениями)?
При этом программирование рекурсии выглядит так. Функция должна сначала проверить, не является ли переданный набор параметров простым (крайним) случаем. В этом случае функция должна вернуть значение (или выполнить действия), соответствующие простому случаю. Иначе функция должна вызвать себя рекурсивно для другого набора параметров, и на основе полученных значений вычислить значение, которое она должна вернуть.
Рассмотрим несколько примеров (на самом деле эти примеры являются «учебными» и все перечисленные задачи гораздо лучше решать при помощи циклов, а не рекурсией).
