Питон для нормальных. Учебник Москва Базальт спо макс пресс 2018
Скачать 2.54 Mb.
|
20, как выдала наша программа (рис. 3.3). В чём же проблема? Для выявления логических ошибок применяется такой приём, как тестиро- вание. Вы уже неосознанно прибегали к нему ранее. Тестирование — это состав- ление входных данных для программы, для которых вы можете сами составить выходные. Совокупность набора входных данных и соответствующих им выход- ных данных называется «тестом». В нашем случае весь тест — это два числа: входу 5 соответствует выход 30. Для сложных программ тесты будут сложнее и больше, и их понадобится не один, а много, чтобы охватить как можно больше разных вариантов поведения программы. Когда факт наличия ошибки установлен, нужно найти конкретное место, где она возникла и устранить её. Для этого используется отладка. Отладка — это пошаговое исполнение программы с выводом промежуточных результатов, кото- рое позволяет определить, в промежутке между какими операторами произошла логическая ошибка. В компилируемых языках программирования таких, напри- мер, как Pascal и С, для отладки применяется специализированная программа- отладчик. В интепретируемых языках, в частности в Python, в этом нет большой необходимости, поскольку программа и так выполняется пошагово, и вы можете вывести любые данные в любой момент с помощью стандартной функции print. При отладке важно суметь сформулировать гипотезу: «что нужно проверить»? 3.4. Отладка программы 85 Иногда это удаётся не с первого раза. Попробуем рассмотреть это на нашем при- мере. Итак, первая гипотеза: счётчик i принимает не те значения, попробуем выводить его значения в цикле: N = i n t ( i n p u t ( ’Введите N : ’ )) s = 0 f o r i i n r a n g e ( N ): p r i n t ( i ) s = s + i *2 p r i n t ( s ) Получим: Введите N: 5 0 1 2 3 4 20 Как видим, со счётчиком всё в порядке. Тогда проверим, всё ли в порядке с очередным элементом суммы: N = i n t ( i n p u t ( ’Введите N : ’ )) s = 0 f o r i i n r a n g e ( N ): s = s + i *2 p r i n t ( i *2) p r i n t ( s ) Получим: 0 2 4 6 8 20 Мы получили последовательность 0, 2, 4, 6, 8, в то время как должны были получить 0, 1, 4, 9, 16, значит, наше предположение подтвердилось: очередной элемент суммы вычисляется неверно. Честно говоря, уже на этапе написания отладочного вывода можно было заметить, что i*2 это не совсем то, что нужно, ведь вместо возведения в степень мы написали умножение (забыли одну звёзодч- ку). 86 Глава 3. Циклы В более сложных программах, однако, вам часто придётся проверять по нескольку гипотез и выводить значительное число отладочной информации, что- бы обнаружить точную причину ошибки. Помните: отладка — это мощный и эф- фективный способ борьбы с логическими ошибками, но работает он только тогда, когда вы способны внятно сформулировать гипотезу, т. е. определить, что про- верять. Если начать выводить всё подряд, вы быстро потеряетесь в отладочной информации и ничего не сможете найти. Некоторые наиболее распространённые ошибки были проклассифицированы нами в виде схемы, приведённой на рис. 3.4. Схема не претендует на полноту, но будет полезна для начинающих во многих типичных случаях. 3.5 Задания на циклы Пример задачи 11 Решим популярную задачу по нахождению всех про- стых чисел до некоторого целого числа n. Классический алгоритм ре- шения этой задачи носит название «Решето Эратосфена». Для нахож- дения всех простых чисел не больше заданного числа n, следуя методу Эратосфена, нужно выполнить следующие шаги: 1. Выписать подряд все целые числа от двух до n (2, 3, 4, . . . , n). 2. Пусть переменная p изначально равна двум — первому простому числу. 3. Зачеркнуть в списке числа от 2p до n, считая шагами по p (это будут числа кратные p: 2p, 3p, 4p, . . . ). 4. Найти первое незачёркнутое число в списке, большее, чем p, и при- своить значению переменной p это число. 5. Повторять шаги 3 и 4, пока возможно. 6. Теперь все незачёркнутые числа в списке — это все простые числа от 2 до n. Решение задачи 11 На практике алгоритм можно улучшить следующим об- разом. На шаге №3 числа можно зачеркивать, начиная сразу с числа p 2 , потому что все составные числа меньше него уже будут зачеркнуты к этому времени. И, соответственно, останавливать алгоритм можно, когда p 2 станет больше, чем n. f r o m math i m p o r t sqrt n = i n t ( i n p u t ( "вывод простых чисел до ... " )) a = l i s t ( r a n g e ( n )) # создаём список из n элементов # Вторым элементом является единица, которую не # считают простым числом. Забиваем её нулем: a [1] = 0 3.5. Задания на циклы 87 Рис. 3.4. Возможные источники ошибок и алгоритм их нахождения. 88 Глава 3. Циклы # Перебор всех элементов до заданного числа: f o r p i n r a n g e (2 , i n t ( sqrt ( n ))+1): i f a [ p ] != 0: # если он не равен нулю, то j = p ** 2 # удвоить: текущий элемент простое число w h i l e j < n : a [ j ] = 0 # заменить на 0 j = j + p # перейти в позицию на m больше # Вывод простых чисел на экран: b = [] f o r i i n a : i f a [ i ] != 0: b . append ( a [ i ]) p r i n t ( b ) Вывод программы: вывод простых чисел до числа ... 70 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67] Задание 8 (Задания на цикл с условием) Выполнять три задания в за- висимости от номера в списке группы в алфавитном порядке. Необходи- мо сделать задания №m, №m+5, №m+10, m=(n-1)%5+1, где n — номер в списке группы. 1. Напишите программу, которая будет суммировать вводимые с клавиатуры числа до тех пор, пока они положительны. 2. Напишите программу, которая будет суммировать вводимые с клавиатуры числа до тех пор, пока они отрицательны. 3. Напишите программу, которая будет суммировать вводимые с клавиатуры числа до тех пор, пока они не равны нулю. 4. Напишите программу, которая будет суммировать вводимые с клавиатуры числа до тех пор, пока они чётные. 5. Дано число n. Напечатать те натуральные числа, квадрат которых не пре- вышает n. 6. Дано число n. Найти первое натуральное число, квадрат которого больше n. 7. Дано число n. Среди чисел 1, 1 + 1 2 , 1 + 1 2 + 1 3 , . . . найдите первое, большее числа n. 8. Дано число a (1 6 a 6 1.5). Среди чисел 1 + 1 2 , 1 + 1 3 , 1 + 1 4 , . . . (заметим, что каждое следующее число в последовательности меньше предыдущего) найдите первое, меньшее a. 3.5. Задания на циклы 89 9. Напишите программу, которая запрашивает у пользователя числа до тех пор, пока каждое следующее число больше предыдущего. В конце програм- ма сообщает, сколько чисел было введено. 10. Напишите программу, которая запрашивает у пользователя числа до тех пор, пока каждое следующее число меньше предыдущего. В конце програм- ма сообщает, сколько чисел было введено. 11. Напишите программу, которая запрашивает у пользователя числа до тех пор, пока каждое следующее число целое. В конце программа сообщает, сколько чисел было введено. 12. Напишите программу, которая запрашивает у пользователя числа до тех пор, пока каждое следующее число меньше 10. В конце программа сообща- ет, сколько чисел было введено. 13. Дано натуральное число, в котором все цифры различны. Определить по- рядковый номер его максимальной цифры, считая номера: от конца числа; от начала числа. 14. Дано натуральное число, в котором все цифры различны. Определить по- рядковый номер его минимальной цифры, считая номера: от конца числа; от начала числа. 15. Дано натуральное число. Определить, сколько раз в нем встречается мак- симальная цифра (например, для числа 132233 ответ равен 3, для числа 46336 — двум, для числа 12345 — одному). Задание 9 (Задания на цикл со счётчиком) Выполнять три задания в зависимости от номера в списке группы в алфавитном порядке. Необ- ходимо сделать задания №m, №m+5, №m+10, m=(n-1)%5+1, где n — номер в списке группы. 1. Напишите программу, вычисляющую сумму всех чётных чисел в диапазоне от 1 до 90 включительно. 2. Напишите программу, вычисляющую сумму всех чётных чисел в диапазоне от a до b включительно (вводятся с клавиатуры). 3. Напишите программу, вычисляющую сумму всех нечётных чисел в диапа- зоне от 1 до 90 включительно. 4. Напишите программу, вычисляющую сумму всех нечётных чисел в диапа- зоне от a до b включительно (вводятся с клавиатуры). 90 Глава 3. Циклы 5. Напечатайте таблицу умножения на 5, желательно печатать в виде: 1 × 5 = 5 2 × 5 = 10 9 × 5 = 45 Вместо знака умножения × можно использовать строчную латинскую бук- ву «x». 6. Напечатайте таблицу умножения на 9, желательно печатать в виде: 1 × 9 = 9 2 × 9 = 18 9 × 9 = 81 Вместо знака умножения × можно использовать строчную латинскую бук- ву «x». 7. Напечатайте таблицу умножения на целое число n, n вводится с клавиату- ры (2 6 n 6 9), желательно печатать в виде: 1 × n = . . . 2 × n = . . . 9 × n = . . . Вместо знака умножения × можно использовать строчную латинскую бук- ву «x». Внимание! Не нужно печатать символ n, вместо этого нужно печа- тать введённое значение. 8. Напечатать таблицу стоимости 50, 100, 150, . . . , 1000 г сыра (стоимость 1 кг сыра вводится с клавиатуры). 9. Напечатать таблицу стоимости 100, 200, 300, . . . , 2000 г конфет (стоимость 1 кг конфет вводится с клавиатуры). 10. Найти сумму всех целых чисел от 10 до 100; 11. Найти сумму всех целых чисел от a до 100 включительно (значение a вво- дится с клавиатуры). 12. Найти сумму всех целых чисел от 10 до b включительно (значение b вво- дится с клавиатуры). 13. Найти сумму всех целых чисел от a до b включительно (значения a и b вводятся с клавиатуры). 3.5. Задания на циклы 91 14. Найти произведение всех целых чисел от 10 до 100 включительно. Обратите внимание, что Python может работать с целыми числами неограниченного размера! 15. Найти произведение всех целых чисел от a до b включительно (значения a и b вводятся с клавиатуры). Задание 10 (Задания на комбинацию циклов со счётчиком и условием) Выполнять одно задание с номером (n-1)%8+1 в зависимости от номера n в списке группы в алфавитном порядке. 1. За столом сидят n гостей (вводится с клавиатуры), перед которыми сто- ит пирог. Пирог и его части можно делить только пополам. Определите, сколько раз нужно делить пирог на ещё более мелкие части, чтобы: • каждому из гостей достался хотя бы 1 кусок; • как минимум половине гостей досталось по 2 куска; • каждому гостю досталось по 1 куску и при этом ещё хотя бы 10 кусков осталось в запасе. 2. Ученик 4-го класса Василий время от времени начинает прогуливать школу. Первый раз он прогуливает 2 дня в конце первого месяца, через месяц — 3 дня, ещё через месяц — 4 дня и так далее. За каждый день прогулов Василию ставят по 2 двойки, плюс ещё по 3 двойки он получает в месяц на занятиях. Сколько раз Василий может прогуливать школу (сколько раз уйти в «загул») и сколько дней прогуляет, чтобы не быть отчисленным, если отчисление грозит ему за 70 двоек? Продолжительность учебного года — 9 месяцев, выйти из «загула» досрочно (не прогуляв положенное число дней) Василий не в состоянии, каникулами пренебречь. 3. В детском садике n детей играют в следующую игру. Перед ними гора из m кубиков, первый ребёнок вынимает из кучи 1 кубик, каждый последующий ребёнок — в два раза больше предыдущего и так по кругу. Если число куби- ков, которые нужно вынуть, превышает 25, из него вычитается 25 и отсчёт идёт от уменьшенного числа, например, вместо 32 кубиков будет вынуто 7, затем 14 и т. д. Проигравшим считается тот, кто не смог вытащить нужное число кубиков (в куче осталось недостаточно). Определите проигравшего. 4. Последовательность Фибоначчи определяется рекуррентным соотношени- ем x n+1 = x n + x n−1 , где x 0 = 1 и x 1 = 1. Найти первое число в последова- тельности Фибоначчи, которое больше 1000. 5. Для n-го члена в последовательности Фибоначчи существует явная форму- ла: x n = 1 √ 5 1 + √ 5 2 ! n+1 − 1 − √ 5 2 ! n+1 92 Глава 3. Циклы Поскольку операции с вещественными числами происходят с конечной точ- ностью, то с ростом n, результат вычисления по этой формуле будет все больше отличаться от настоящего числа Фибоначчи. Найдите n, начиная с которого, отличие от истинного значения превысит 0.001. 6. Создайте программу, играющую с пользователем в орлянку. Программа должна спрашивать у пользователя: орёл или решка. Если пользователь вводит 0, то выбирает орла, 1 — решку, любое другое число — конец игры. Программа должна вести учёт выигрышей и проигрышей и после каждого раунда сообщать пользователю о состоянии его счёта. Пусть вначале на счету 3 рубля и ставка в каждом коне 1 рубль. Если денег у пользователя не осталось — игра прекращается. 3 7. Гражданин 1 марта открыл счет в банке, вложив 1000 руб. Через каждый месяц размер вклада увеличивается на 2% от имеющейся суммы. Опреде- лить: • за какой месяц величина ежемесячного увеличения вклада превысит 30 рублей; • через сколько месяцев размер вклада превысит 1200 руб. 8. Начав тренировки, лыжник в первый день пробежал 10 км. Каждый сле- дующий день он увеличивал пробег на 10% от пробега предыдущего дня. Определить: • в какой день он пробежит больше 20 км; • в какой день суммарный пробег за все дни превысит 100 км. 3 Выпал орёл или решка, программа определяет с помощью функции randint(a, b) из стан- дартного модуля random, которая возвращает случайное целое число n, a 6 n 6 b. Глава 4 Функции 4.1 Функции в программировании Функции в программировании можно представить как изолированный блок кода, обращение к которому в процессе выполнения программы может быть мно- гократным. Зачем нужны такие блоки инструкций? В первую очередь, чтобы со- кратить объем исходного кода: рационально вынести часто повторяющиеся вы- ражения в отдельный блок и затем по мере надобности обращаться к нему. Для того, чтобы в полной мере осознать необходимость использования функ- ций, приведём сложный, но чрезвычайно полезный пример вычисления корня нелинейного уравнению с помощью метода деления отрезка пополам. Пусть на интервале [a; b] имеется ровно 1 корень уравнения f (x) = 0. Значит, f (a) и f (b) имеют разные знаки. Используем этот факт. Найдём f (c), где c = a+b 2 Если f (c) того же знака, что и f (a), значит корень расположен между c и b, иначе — между a и c. Пусть теперь начало нового интервала (будь то a или c в зависимости от того, где находится корень) обозначается a 1 (что означает после первой итерации), а конец, соответственно, b 1 . Исходные начало и конец также будем обозначать a 0 и b 0 для общности. В результате нам удасться снизить неопределённость того, где находится корень, в два раза. Такой процесс можно повторять сколько угодно раз (при расчёте на компью- тере столько, сколько позволяет точность представления данных ЭВМ), после- довательно заужая интервал, в котором находится корень. Обычно процесс за- канчивают по достижении на n-ой итерации интервалом [a n ; b n ] величины менее некоторого заранее заданного ε. Итак, напишем программу для вычисления корня нелинейного уравнения f (x) = x 2 − 4: f r o m math i m p o r t * a = -10 b = 10 94 Глава 4. Функции f(a) f(c) f(b) f(x) a c b x f(a) f(c) f(b) f(x) a c b x Рис. 4.1. Иллюстрация к методу деления отрезка пополам. w h i l e (b - a ) > 10**( -10): c = ( a + b )/2 f_a = a **2 -4 f_b = b **2 -4 f_c = c **2 -4 i f f_a * f_c > 0: a = c e l s e : b = c p r i n t (( a + b )/2) Если мы захотим вычислить корень другой нелинейной функции, например, f (x) = x 2 + 4x + 4, то придётся переделывать выражения сразу в трёх строч- ках. Кажется логичным выделить наше нелинейное уравнение в отдельный блок программы. Перепишем программу с помощью функции: f r o m math i m p o r t * d e f f u n k c i j a ( x ): f = x **2+4* x +4 r e t u r n f a = -10 b = 10 w h i l e (b - a ) > 10**( -10): 4.1. Функции в программировании 95 c = ( a + b )/2 f_a = f u n k c i j a ( a ) f_b = f u n k c i j a ( b ) f_c = f u n k c i j a ( c ) i f f_a * f_c > 0: a = c e l s e : b = c p r i n t (( a + b )/2) Программный код подпрограммы описывается единожды перед телом основной программы, затем из основной программы можно им пользоваться многократно. Обращение к этому программному коду из тела основной программы осуществ- ляется по его имени (имени подпрограммы). Инструкция def — это команда языка программирования Python, позволя- ющая создавать функцию; funkcija — это имя функции, которое (так же как и имена переменных) может быть почти любым, но желательно осмысленным. После в скобках перечисляются параметры функции. Если их нет, то скобки остаются пустыми. Далее идет двоеточие, обозначающее окончание заголовка функции (аналогично с условиями и циклами). После заголовка с новой строки и с отступом следуют выражения тела функции. В конце тела функции обыч- но присутствует инструкция return, после которой идёт значение или выраже- ние, являющееся результатом работы функции. Именно оно будет подставлено в главной (вызывающей) программе на место функции. Принято говорить, что функция «возвращает значение», в данном случае — результат вычисления вы- ражения x 2 + 4x + 4 в конкретной точке x. В других языках программирования такая инструкция называется также функцией, а инструкция, которая ничего не возвращает, а только производит какие-то действия, называется процеду- рой 1 , например: d e f p r o c e d u r a ( x ): f = x **2+4* x +4 p r i n t ( f ) Те же самые инструкции можно переписать в виде функции Bisection, кото- рой передаются данные из основной программы, и которая возвращается корень уравнения с заданной точностью: |