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

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

1 Биоритмы Давно известно, что творческая и физическая активность человека не остается постоянной, циклически меняется, причем периодичность ее изменения приблизительно согласуется с периодом вращения Луны вокруг Земли. Существует теория, согласно которой физическая, эмоциональная и интеллектуальная активность человека подчиняется соответствующим биоритмам. Каждый биоритм представляет собой синусоиду со строго постоянным периодом, причем для каждого биоритма существует свой период. В отдельные дни все три биоритма человека могут достигнуть своего максимума и тогда человек испытывает подъем творческих и физических сил, в такие дни у него все спорится, он легко решает проблемы, которые в другое время ему решить гораздо сложнее. Точно также существуют и «черные» дни, соответствующие спаду всех трех биоритмов. Используя уже опробованную методику нисходящего программирования, создадим программу, в которой запрашивается дата рождения человека и дата, для которой требуется оценить его состояние. Программа должна рассчитать и выдать на экран ближайшие к этой дате дни пика и спада биоритмов. Алгоритм программы можно укрупнено записать следующим образом: ввести дату рождения и текущую дату, проконтролировать их правильность и непротиворечивость; вычислить количество дней между двумя датами, чтобы определить фазу синусоид для текущей даты; вычислить количество дней от текущей даты до даты ближайшего пика биоритмов и даты ближайшего спада; определить и напечатать обе даты. Будем считать, что каждое из перечисленных действий реализуется в отдельной процедуре, тогда начальный вариант программы будет таким: Procedure InputDates( do,mo,yo,d,m,y: Integer); ; Procedure Get_count_pf_days (do,mo,yo,d,m,y: Integer; days: Integer);

3 WriteDates (dmin, dmax, days). Начинаем детализацию программы. Прежде всего подумаем, как по двум датам вычислить разделяющее их количество дней? Если вспомнить, что следует учитывать неодинаковое количество дней по месяцам года, а также 29 февраля для високосных лет, то ответ на этот вопрос окажется не таким уж простым. Предлагаемый алгоритм подсчета количества дней заключается в вычислении количества дней от даты рождения до конца месяца, а затем и года рождения, количества дней, от начала текущего года до текущего месяца и текущей даты, а также - в подсчете количества полных лет, разделяющих обе даты. Количество лет затем легко пересчитывается в количество дней с учетом длины года (365 дней для обычных и 366 дней для високосных лет). Это очень прямолинейный алгоритм, но, откровенно говоря, мне не пришло в голову ничего другого. Возможно, существует более изящный способ подсчета и Вы его знаете, тогда программная реализация будет другой. Упростить алгоритм можно за счет создания и использования массива из 12 целых чисел, содержащего количества дней по месяцам невисокосного года, т.е. 31, 28, 31, 30 и т.д. Этот массив (назовем его SIZE_OF_MONTH - длина _месяца) можно использовать и для обратной задачи, т.е. для определения даты критических дней, а также для проверки правильности вводимых дат. Таким образом, массив SIZE OF_MONTH будет использоваться сразу в трех процедурах. Сделаем его глобальным, для чего его описание поместим перед описанием процедур: const Size_of_Month: array - [1..12] of Byte = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); Procedure InputDates ( d0,m0,y0,d,m,y: Integer);. Поскольку описание массива размещается до описания процедур, он становится доступным внутри каждой из процедур и служит для них глобальным. В отличие от этого все константы и переменные, объявляемые внутри некоторой процедуры, являются локальными и могут использоваться только в этой процедуре. С учетом сказанного напишем следующий начальный вариант программной реализации процедуры INPUTDATES: Procedure InputDates( d0,m0,y0,d,m,y: Integer); correctly: Boolean; repeat correctly := у > у0; if not correctly and (у = y0) then correctly := m > m0; if not correctly and (m = m0) then correctly := d>=d0 until correctly ; В этой процедуре дважды выполняется одно и то же алгоритмическое действие (ввод и контроль даты). Это действие можно вынести в отдельную внутреннюю процедуру с именем INPDATE, тогда получим следующий окончательный вариант: Procedure InputDates( d0,m0,y0,d,m,y : Integer); correctly: Boolean; Procedure InpDate (text: String; d,m,y: Integer);

5 const YMIN = 1800; YМАХ = 2000; repeat Write (text); ReadLn (d,m,y) ; correctly := (y >= YMIN) and (Y <= YMAX) and (m >= 1) and (m <= 12) and (d > 0) ; if correctly then if (m = 2) and (d = 29) and (y mod 4=0) then else correctly := d <= Size_of_Month[m] ; if not correctly then WriteLn (' Ошибка в дате!') until correctly ; repeat InpDate ('.Введите дату рождения в формате ДД ММ ГГГГ:',d0,m0,y0) ; InpDate (' Введите текущую дату: ',d,m,y);

6 correctly := у > у0; if not correctly and (y = y0) then correctly := m > m0; if not correctly and (m = m0) then correctly := d >= d0 until correctly ; В самом общем виде алгоритм подсчета количества дней, разделяющих две даты, описан выше. При его реализации следует учесть три возможных варианта: месячный младенец (год и месяц обеих дат одинаков): количество дней находится простым вычитанием двух чисел; годовалый младенец (год обеих дат совпадает): количество дней = (остаток дней в месяце рождения) + (количество дней в текущем месяце) + (количество дней в месяцах, разделяющих обе даты); общий вариант (отличаются года): количество дней = (количество дней от даты рождения до конца года) + (количество дней в разделяющих даты годах) + (количество дней от начала текущего года до текущей даты). С учетом этого составим начальный вариант программной реализации процедуры GET_NUMBERS_OF_DAYS : Procedure Get_numbers_of_days (d,m,y,d,m,y: Integer; days: Integer); Procedure Variant2; ;

7 Procedure Variant3 ; ; if (y = y0) and (m = m0) then days := d - d0 else days := d + Size_of_Month [m0] - d0; if (y0 mod 4=0) and (m0 = 2) then inc(days); if у = y0 then Variant2 else Variant3 ; В этом фрагменте используется способ связи вспомогательных процедур VARIANT2 и VARIANT3 с основной процедурой через глобальные переменные, которыми являются параметры обращения к основной процедуре. Вспомогательные процедуры удобнее всего реализовать на основе циклов WHILE: Procedure Variant2 ;

8 mm : Integer; mm : = m0 ; while mm < m do days := days + Size_of_Month [mm] ; if (mm = 2) and (y0 mod 4=0) then inc (days) ; inc (mm) ; Procedure Variant3; mm/ УУ : Integer; mm : = m0 + 1 ; while mm <= 12 do days := days+size_of_month [mm] ; if (mm = 2) and (y0 mod 4=0) then inc (days) ; inc (mm)

9 ; yy := y0 + 1; while yy < у do days : = days + 365; if yy mod 4=0 then inc (days) ; inc (yy) ; mm : = 1 ; while mm < m do days := days + Size_of_Month [mm] ; if (y mod 4=0) and (mm = 2) then inc (days) ; inc (mm) ; В процедуре FINDMAXMIN осуществляется поиск критических дней, т.е. ближайших к текущей дате дней, для которых все три биоритма достигают своего максимума и минимума. Предполагается, что биоритмы изменяются по законам синуса от количества прожитых дней с периодами ТF, ТE и TI соответственно для физической, эмоциональной и интеллектуальной активности человека. В программе приняты следующие периоды (в днях): Знакомство с языком Турбо Паскаля TF= ТЕ= TI=

10 Самый простой алгоритм поиска заключается в том, чтобы вычислить значения сумм всех трех синусоид для текущего дня и для каждого из последующих дней на некотором заранее обусловленном интервале, например, в пределах месяца. Сопоставив результаты расчетов для каждого дня, нетрудно определить критические дни: Procedure FindMaxMin( dmin,dmax: Integer; days: Integer); const TF = 2*3.1416/ ; ТЕ = 2*3.1416/ ; TI = 2*3.1416/ ; INTERVAL =30; min, max, x : Real; i : Integer; max := sin(days*tf)+sin(days*te)+sin(days*ti); min := max; dmin := days; dmax := days; for i := 0 to INTERVAL do x := sin((days+i)*tf) + sin((days+i)*te) + sin((days+i)*ti); if x > max then

11 max : = x; dmax : = days + i else if x < min then min := x; dmin := days + i ; ; При разработке алгоритма процедуры WRITEDATES, с помощью которой на экран выводится результат работы программы, учтем, что основные сложности будут связаны с определением новой даты по начальной дате и количеству прошедших дней. Этот насчет будет повторяться дважды - для даты пика и даты спада биоритмов, поэтому его следует вынести в отдельную процедуру WRITEDATES. Кроме того, вряд ли Вы откажетесь от возможности вывода на экран дополнительной информации о том, сколько полных дней, часов, минут и секунд разделяют дату рождения человека и текущую дату. Однако реализация этого вывода не столь проста, как это может показаться на первый взгляд. Дело в том, что диапазон возможных значений данных типа INTEGER составляет от до Средняя продолжительность жизни человека - около 70 лет, т.е дней. Это значение еще можно представить в Переменной типа INTEGER, однако часы, минуты и тем более секунды средней продолжительности жизни далеко превышают этот диапазон. Чтобы получить вывод достоверных данных, необходимо расширить диапазон значений целых чисел. Для этого в Турбо Паскале предусмотрен специальный тип данных LONGINT («длинный» целый), имеющий диапазон значений от до (см. гл. 4). Поэтому в процедуре WRITEDATES следует предусмотреть вспомогательную переменную этого типа, присвоить ей значение переменной DAYS и уже затем использовать «длинную» переменную для вычисления (и вывода) часов, минут, секунд. В результате начальный вариант процедуры WRITEDATES может быть таким: Procedure WriteDates (dmin,dmax,days : Integer); < >Procedure WriteDate (text : String; dd : Integer);

12 ; < >LongDays: Longlnt; LongDays : = days ; WriteLn( 'Прошло: ', LongDays,' дней, ', longdays*24, ' часов, ', LongDays*24*60, ' минут, ', LongDays*24*60*60, ' секунд'); WriteDate ( 'Наименее благоприятный день: ', drain); WriteDate ( 'Наиболее благоприятный день: ',dmax) ; Реализация процедуры WRITEDATE не вызывает особых сложностей: Procedure WriteDate (text: String; dd: Integer); const Names_of_Monthes : array [1..12] of String [3] =('янв','фев','мар','апр','мая', 'июн','июл','авг','сен','окт', 'ноя','дек'); d0,m0,y0,ddd : Integer; d0 := d; m0 := m; y0 : = y;

13 ddd := days; while ddd<>dd do inc(d0); if (y0 mod 4 <> 0) and (d0 > Size_of_Month[m0]) or (y0 mod,4=0) and (d0=30) then d0 := 1; inc(m0); if m0 = 13 then m0 := 1; inc(y0) ; inc(ddd) ; WriteLn(text,d0,'-',Names_of_Monthes[m0],'-',y0) ; Собрав воедино отдельные части, получим полный текст программы (прил.5.2), предназначенной для определения биоритмов.

📎📎📎📎📎📎📎📎📎📎