1. Решение задач о нахождении суммы ряда Числовым рядом называется бесконечная сумма некоторой S последовательности. S = a1+a2+a3+…+ai+… = a i 1 i С помощью разложения в числовой ряд можно вычислить многие из элементарных функций, например x3 x5 x7 x9 sin x x ... , 3! 5! 7! 9! x 2 x 4 x 6 x8 cos x 1 ... при 0 x ; 2! 4! 6! 8! 4 x 2 x3 x 4 x5 e 1 x ... при x 1 . 2! 3! 4! 5! x Поскольку ряд имеет бесконечное число членов, вычисления производят с определенной точностью, т.е. суммирование прекращают, когда очередной член ряда оказывается меньше допустимой погрешности вычислений. Допустимую погрешность вычислений называют иначе точностью вычислений. Она задается малым числом , где 0<<1, (=10-2, 10-3,…), чем меньше , тем точнее решение. При =10-i решение будет точным до i-го знака после запятой. Основная схема вычисления бесконечной суммы с заданной точностью: Var S:Real; a:Real; {значение суммы} {очередной член суммы} eps:Real; {требуемая точность вычислений} . . . Begin . . . S:=0; {Начальное значение суммы устанавливаем равным 0} a:=a1; {Присваиваем а значение первого члена ряда} 1 While (abs(a)>eps) Do Begin {сравниваем очередной член ряда} {c требуемой точностью} S:=S+a; {добавляем очередной член в сумму} a:=...; {вычисляем значение следующего члена ряда} End; End. Основная проблема при вычислении суммы числового ряда состоит в вычислении очередного члена последовательности. Можно выделить три подхода к решению этой проблемы: 1) использование формулы общего члена ряда; 2) использование рекуррентного соотношения; 3) смешанный подход, основанный на двух предыдущих. Использование формулы общего члена ряда Формула общего члена ряда это соотношение, с помощью которого можно вычислить очередной член ряда, используя его номер. Так для ряда S = 2+4+6+8+10+… a1=2=2∙1, a2=4=2∙2, a3=6=2∙3, … , и, соответственно, формула общего члена: ai=2∙i, где i=1, 2, 3,… . Для ряда xi x2 x3 S 1 x ... , формула общего члена ai , где i! 2! 3! i=0, 1, 2, 3, … . Для первого ряда формула общего члена получилась довольно простая и вычисление очередного члена ряда на основе этой формулы не составит труда. Для второго ряда проведение вычислений очередного члена ряда на основе выведенной формулы будет неэффективно, т.к. потребует использования вложенных циклов. Поэтому данный метод для вычисления очередного члена ряда используется лишь в том случае, если формула является легко вычислимой. Пример 2.1. Найти сумму ряда с точностью =10-4. S 1 1 1 1 ... ... 2 3 n . Формула общего члена ряда: 2 1 i ai= , i=1, 2, 3,… Поскольку эта формула легко вычислима, используем ее при составлении алгоритма. Const eps=1E-4; {константа eps задана в экспоненциальной форме и равна 0.0001} Var a,S:Real; i:Integer; Begin S:=0; i:=1; a:=1; While (abs(a)>eps) Do Begin S:=S+a; i:=i+1; a:=1/i; End End. Задание. Найти сумму ряда, заданного в примере Пример 2.1, с максимальной возможной точностью? Посчитать, сколько итераций для этого потребуется. Использование рекуррентного соотношения Понятие рекуррентной последовательности в курсе математики вводится так: пусть известно k чисел: а1, …, ak. Эти числа являются началом числовой последовательности. Следующие элементы этой последовательности вычисляются так: ak+1 = F(a1, …, ak); ak+2 = F(a2, …, ak+1); ak+3 = F(a3, …, ak+2) … Здесь F(…) – функция от k аргументов. Формула вида ai = F(ai-k, …, ai-1) называется рекуррентной формулой. Другими словами, рекуррентная последовательность – это бесконечный ряд чисел, каждое из которых, за исключением k начальных, вычисляется через предыдущие члены ряда. 3 Например, арифметическая и геометрическая прогрессии: 1, если i 1, a1=1, a2=3, a3=5,… Рекуррентная формула: ai . ai 1 2, если i 1 1, если i 1, a1=1, a2=2, a3=4, … Рекуррентная формула: ai . ai 1 2, если i 1 Глубина рекурсии в обоих случаях равна 1 (такую зависимость называют одношаговой рекурсией). Числа Фибоначчи: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, … Начиная с третьего элемента, каждое число равно сумме двух предыдущих, т.е. это рекуррентная последовательность с глубиной, равной 2. Рекуррентная формула для чисел последовательности Фибоначчи: 1, если i 1, i 2, fi . f i 1 f i 2 , если i 2 Для вывода рекуррентной формулы часто можно воспользоваться соотношением вида: ai f (i ) . ai 1 Получив f(i), мы по сути найдем основную часть рекуррентного соотношения, так как ai ai1 f (i) . Правда, при этом нельзя забывать о начальном условии, без которого рекуррентная формула не будет полной. x 2 x3 ... . Определим рекуррентное соотношение для ряда: S 1 x 2! 3! x0 x1 xi x i 1 1; a1 x; ai ; ai 1 Положим a0 . Тогда 0! 1! i! (i 1)! ai x i (i 1)! x f (i ) . i 1 ai1 x i! i 4 1, если i 0 Получаем рекуррентное соотношение: ai . x ai 1 , если i 0 i Рекуррентное соотношение используется в тех случаях, когда следующий член ряда можно выразить через предыдущий (или предыдущие), а использование формулы общего члена приведет к появлению вложенных циклов, что сделает программу неэффективной. Пример 2.2. Написать программу вычисления суммы N первых членов x 2 x 4 x 6 x8 ряда S 1 ... . Выпишем члены ряда 2! 4! 6! 8! a0 1, a1 x2 x4 x 2i x 2(i 1) , a2 , ai (1) i , ai 1 (1) i 1 . 2! 4! (2i)! (2 (i 1))! Поскольку каждый член ряда может быть получен из предыдущего домножением на определенный множитель, а вычисление «в лоб» каждого члена ряда приведет к появлению вложенных циклов, эффективнее будет использовать рекуррентное соотношение. Выведем его ai x 2i (1) i (2 (i 1))! x2 2(i 1) ai 1 (2i 1) (2i) x (1) i 1 (2i)! 1, если i 0 x2 Полученное рекуррентное соотношение ai a . , если i 0 i 1 (2i 1) (2i ) Var i,N:integer; x,a,S:real; Begin Write(’Введите число членов ряда ’);ReadLn(N); Write(’Введите x ’);ReadLn(x); a:=1; S:=0; For i:=1 To N Do Begin S:=S+a; a:=-a*x*x/(2*i-1)/2/i; End; 5 WriteLn(‘S=’,S) End. Одновременное использование формулы общего члена и рекуррентного соотношения Оба рассмотренных выше способа: использование формулы общего члена и построение рекуррентного соотношения не исчерпывают всего многообразия числовых рядов. Может возникать ситуация, когда формула общего члена не является эффективно вычислимой и при этом невозможно построить рекуррентное соотношение. Часто такая ситуация находит свое разрешение, если каждый член ряда представить в виде произведения ai=bi∙ci и отдельно рассмотреть последовательности из bi и При ci . этом одна из последовательностей будет эффективно вычислима через общий член ряда, а другая через рекуррентное соотношение. Рассмотрим ряд S x x2 x3 ... 2 3 . xi 1 Формула общего члена аi , i 1, 2, 3, ... . Представим ai=bi∙ci , bi=xi, сi . i i Последовательность из выражается bi рекуррентным соотношением 1, i 0 , а последовательность из ci эффективно вычислима через bi bi 1 x, i 0 формулу общего члена. Пример 2.3. Найти сумму ряда S 1 Определить сколько членов ряда x 2 x 4 x8 ... c точностью ε. 2 3 4 требовалось просуммировать для достижения заданной точности. Определим общий вид слагаемого ряда: i x2 ai (1) , i 1, 2, 3, ..., bi (1) i x 2 , ci 1 . i 1 i 1 i i Выведем рекуррентное соотношение для bi : i 1 i 1 2 b1= –x , b2=x , b3= –x , bi (1) x , bi 1 ( 1) x . 2 4 8 i 2i 6 1, i 0 ai , bi ci , i 0 ( i 11 ) bi (1)i x 2 x2 2 bi1 (1)i1 x 2 x i i 1 i 1 i 1 x(2 2 x 2 ) i 1 i 1 i 1 x ( 2 2 2 x i 1 ) i 1 i 1 x2 x2 2 x x2 i 1 i 1 1, i 0 Получаем bi . Однако, полученное рекуррентное 2 b ( x ), i 0 i 1 i 1 соотношение так же породит вложенные циклы, т.е. не является эффективно вычислимым. Попробуем bi так же представить в виде произведения. Пусть bi=di∙ei , di (1) , i ei x 2 i . Рекуррентные соотношения для новых последовательностей: 1, i 0 x2 , i 1 1, i 0 di , ei . 2 d ( 1 ), i 0 e x , i 0 e e , i 1 i 1 i 1 i 1 i 1 i 1 Var i:integer; x,S,eps,a,d,e:Real; Begin Write(’Введите x ’);ReadLn(x); Write(’Введите точность вычислений ’);ReadLn(eps); S:=0; a:=1; i:=0; d:=1; While abs(a)>eps do begin S:=S+a; {Добавляем очередной член в сумму} i:=i+1; {Учитываем сколько членов просуммировали} d:=-d; {Вычисляем знак очередного члена} if i=1 then e:=x*x else e:=e*e; a:=d*e/(i+1); {Вычисляем} {очередной} {член ряда} end; WriteLn(’Сумма ряда ’,S); writeLn(’Для достижения точности ’,eps,’требовалоcь’); WriteLn(’просуммировать ’,i,’ членов ряда.’); End. Если все три рассмотренных способа не позволят получить эффективное вычисление очередного члена ряда, тогда необходимо будет использовать механизм вложенных циклов. 7 2. Вложенные циклы Для решения задач часто приходится использовать две и более циклические конструкции, одна из которых располагается внутри другой. Такие конструкции называются вложенными циклами. При этом сочетание циклов For, While, Repeat могут быть любыми. Цикл, который содержит в себе другой – называется внешним. Цикл, находящийся в теле первого – внутренним (вложенным). Правила организации как внешнего, так и внутреннего циклов такие же, как и для простого цикла каждого из этих видов. Использовать вложенные циклы рекомендуется только в тех случаях, когда более эффективной (приводящей к выполнению меньшего числа действий) программу сделать не удается. Например, пусть некоторую задачу можно решить, используя два вложенных цикла, каждый из которых делает n действий, общее число действий будет равно n2. Если, решая эту же задачу, удастся обойтись одним циклом с числом действий равным даже 2 n, это все равно будут эффективнее использования вложенных циклов. При вложении циклов для каждой итерации внешнего цикла внутренний цикл выполняется полностью. Например, для вложенных циклов For: На первой итерации внешнего цикла внутренний цикл выполняется полностью от начального до конечного значения, при неизменном значении параметра внешнего цикла. После этого значение параметра внешнего цикла изменяется (например, увеличивается на 1), и опять от начала до конца выполняется вложенный цикл. И так повторяется до тех пор, пока значение параметра внешнего цикла не станет больше конечного значения, определяемого во внешнем цикле. Пример 3.1. Даны натуральные числа n и k. Составить программу вычисления выражения 1k+2k+3k+…+nk. Var n,k,y,S,i,j:integer; Begin Writeln(‘Введите исходные данные n и k’); 8 ReadLn(n,k); S:=0; For i:=1 To n Do Begin y:=1; For j:=1 To k Do y:=y*i; {вычисление степени k числа i} S:=S+y End; Writeln(‘Ответ ‘,S) End. Пример 3.2. Дано натуральное число N. Необходимо выполнить над этим числом следующие действия. Сложить все цифры числа, получив новое число. Сложить цифры вновь полученного числа, получив очередное число для обработки. Продолжать процесс до тех пор, пока не будет получено число, состоящее из одной цифры. Написать программу для нахождения такого однозначного числа. В конце вывести исходное число и однозначное число, полученное в результате преобразований. Var n,k,s:LongInt; Begin Writeln(n); s:=n; While s>9 Do Begin k:=s; s:=0; Repeat s:=s+k Mod 10; k:=k Div 10 Until k=0 End; Writeln(‘Из числа ‘,n,’ получилось ’,s) End. Пример 3.3. Дан фрагмент программы. целочисленной переменной s после его выполнения. s:=128; 9 Определите значение For i:=1 to 4 do For j:=2 to 3 do s:=s–(i+j); Мы имеем два вложенных цикла For. Присутствие операторных скобок begin … end здесь не обязательно, т.к. одни оператор подсоединяется к оператору цикла в любом случае, а вложенный цикл For j:=2 to 3 do s:=s–(i+j) так же рассматривается как один оператор. Для определения значений переменных в ходе выполнения программы составим трассировочную таблицу (см. табл. 8): Таблица 8. i j s – – 128 1 2 125 1 3 121 2 2 117 2 3 112 3 2 107 3 3 101 4 2 95 4 3 88 Ответ: в результате выполнения данного фрагмента s будет равно 88. Пример 3.4. Вводится последовательность целых ненулевых чисел. Выяснить, есть ли в ней хотя бы одна пара рядом стоящих отрицательных чисел. Количество чисел, вводимых пользователем, не определено, но не меньше двух. После ввода очередного числа программа должна спрашивать, желает ли пользователь продолжать ввод. Ответ пользователя на такой вопрос должен быть только Y (“Yes”) или N (“No”). Program neg; Var a,a1:Integer; b:Boolean; answer:Char; Begin Write(‘Введите число ’); 10 ReadLn(a); b:=false; {считаем, что таких чисел нет} Repeat Write(‘Введите число’); ReadLn(a1); b:=(a<0) and (a1<0) or b; a:=a1; {сохраняем предыдущий элемент последовательности} repeat write(’Продолжать ввод? (Y/N) ’); readLn(answer); until (answer=’Y’)or(answer=’y’)or(answer=’N’)or(answer=’n’); until (answer=’N’)or(answer=’n’); If b Then Writeln(‘Имеются два рядом стоящих отрицательных числа’) Else Writeln(‘Рядом стоящих отрицательных чисел нет’) End. Для того чтобы исключить неверный ввод пользователя на вопрос о продолжении ввода использован вложенный цикл repeat. Пример 3.5. Написать программу, которая находит и выводит на печать все четырёхзначные abcd числ, где a, b, c, d - различные цифры, для которых выполняется: ab – cd = a + b + c + d. Использовать 4 вложенных цикла for – по одному для каждой цифры числа. Program abcd; Var a,b,c,d:Integer; Begin for a:=1 to 9 Do for b:=0 to 9 Do for c:=0 to 9 Do for d:=0 to 9 do If a*10+b(c*10+d)=a+b+c+d Then write (a*1000+b*100+c*10+d,’ ‘) End. 11