Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Задачник.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2 Мб
Скачать
☆

Глава 1 Начала

Задачи этой главы для тех, кто не имеет достаточного опыта в программировании. Они должны помочь преодолеть психологический рубеж создания первых программ. Они полезны и тем, кто уже умеет программировать, но не писал программы на C# и не работал в среде Visual Studio 2005.

Методические указания к главе 1

Модели программ

Что должны знать и что должны уметь студенты, осваивающие начала программирования? Вот возможный перечень основных тем:

  • переменная и ее обобщение – объект;

  • тип переменных и его обобщение – класс;

  • встроенные типы (классы);

  • процесс вычислений, как последовательное выполнение операторов языка;

  • ввод и вывод данных;

  • ветвление процесса вычислений – альтернатива и разбор случаев;

  • циклические вычисления;

  • модульность построения программ;

  • процедуры и функции, как простейшие виды программных модулей;

  • строковый тип и работа с текстами;

  • массивы как структуры данных;

  • рекуррентные вычисления;

  • память и время – два основных ресурса, используемых программами;

  • корректность программ;

  • основы отладки программ и инструментарий среды разработки Visual Studio .Net ;

  • Windows-приложения, визуальное программирование, управляемое событиями;

  • формы и основные элементы управления – командные кнопки, текстовые окна, списки.

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

Что можно не требовать от студентов, осваивающих начала программирования? Можно не требовать умения создавать программную систему, представляющую множество классов, связанных теми или иными отношениями. Более того, вначале можно не требовать создания собственного класса, - можно исходить из более простых моделей программирования, вполне реализуемых в рамках программирования на C# в среде Visual Studio .Net.

Модель 60-х годов – модель языка Pascal и структурного программирования

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

В консольном приложении роль выполняемой программы играет процедура Main. На начальных этапах у программиста нет необходимости создавать собственные классы. Все, что от него требуется, – это добавить в процедуру Main объявления переменных встроенных типов и записать исполняемый блок – последовательность выполняемых операторов. В зависимости от предпочтений преподавателя можно требовать, чтобы все объявления переменных были собраны в начале программы и предшествовали исполняемому блоку, как это требовалось в Pascal-программах 60-х годов.

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

Вот как может выглядеть решение одной из задач первой главы задачника, полностью отвечающее этой модели:

using System;

namespace Ch1_Example1

{

/// <summary>

/// Класс, содержащий выполняемую программу

/// </summary>

class Class1

{

/// <summary>

/// Выполняемая программа!

/// нахождение корней квадратного уравнения:

/// ax^2 +bx +c =0

/// </summary>

[STAThread]

static void Main(string[] args)

{

//объявление переменных

double a,b,c; //коэффициенты уравнения

double x1, x2; // корни уравнения

double d; //дискриминант уравнения

string mes; //сообщение о результатах вычислений

string init; //строка ввода

// ввод исходных данных

Console.WriteLine("Введите три вещественных числа - a, b, c ");

init = Console.ReadLine();

a = Convert.ToDouble(init);

init = Console.ReadLine();

b = Convert.ToDouble(init);

init = Console.ReadLine();

c = Convert.ToDouble(init);

//вычисления и вывод результатов

d = b*b -4*a*c;

if(d>0)

{

mes="Уравнение имеет два вещественных корня!";

Console.WriteLine(mes);

x1 = (-b + Math.Sqrt(d))/(2*a);

x2 = (-b - Math.Sqrt(d))/(2*a);

Console.WriteLine("Корни уравнения: x1={0}, x2={1}",

x1,x2);

}

else if(d==0)

{

mes="Уравнение имеет кратный корень!";

Console.WriteLine(mes);

x1 = -b/(2*a); x2 = -b/(2*a);

Console.WriteLine("Кратный корень уравнения: x={0}",x1);

}

else

{

mes="Уравнение не имеет вещественных корней!";

Console.WriteLine(mes);

}

}

}

}

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

Написание подобных программ требует знания начальных элементов языка C# в пределах первых 8-и лекций. Нужно знать, как создаются и что собой представляют консольные приложения (лекция 1 и 2). В лекции 2 даны начальные сведения о вводе и выводе данных с консоли. Нужно иметь понимание типа данных и встроенных типов данных, прежде всего – строкового типа и арифметических типов. Нужно понимать, как объявляются переменные разных типов и как выполняются преобразования между типами (лекции 3, 4, 5). Нужно знать, как строятся выражения (лекции 6, 7). Ну и наконец необходимо знание операторов языка (лекция 8). Эти же лекции дают первоначальное знакомство со средой программирования. Уже с первых шагов программирования требуется не только знание элементов языка, но и знание возможностей встроенных классов, предоставляемых средой программирования. В частности нужно знать встроенные классы, предоставляющие различные сервисы – Console, Convert, Math, Random а также знание классов, задающих встроенные типы данных –int, double, string, bool.

Следует обращать внимание на качество создаваемых программ, - их надежность, понимание текста, наличие комментариев и тегов summary, описывающих смысл программы.

Модель модульного программирования в процедурах и функциях

Как можно раньше следует вводить понятие модульного программирования и понятия процедур и функций, как модулей простейшего вида. Консольное приложение, строящееся по умолчанию, легко позволяет расширить понятие программы, состоящей из одной процедуры Main, на программу, включающую процедуры и функции. Для этого достаточно добавить в созданный по умолчанию класс Class1 нужные процедуры и функции, которые и будут вызываться из основной процедуры Main. Единственное, не вполне очевидное требование состоит в том, что добавляемые процедуры и функции должны сопровождаться описателем static, объяснение специфической роли которого можно оставить на более поздний этап. Достаточно лишь пояснить, что, если процедура имеет модификатор static, то она может вызывать только процедуры и функции, имеющие этот же модификатор. Поскольку процедура Main объявлена как static процедура, то и вызываемые процедуры и функции следует снабжать этим модификатором.

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

using System;

namespace Ch1_Example2

{

/// <summary>

/// Класс, содержащий выполняемую программу и функцию

/// </summary>

class Class1

{

/// <summary>

/// Выполняемая программа!

/// нахождение интервала, на котором полином третьей степени

/// ax^3 +bx^2 +cx + d

/// меняет знак

/// </summary>

[STAThread]

static void Main(string[] args)

{

//объявление переменных

double a,b,c, d; //коэффициенты полинома

double x1, x2; // исходный интервал

double h; //шаг прохождения интервала

string mes; //сообщение о результатах вычислений

string init; //строка ввода

// ввод исходных данных

Console.WriteLine("Введите коэффициенты полинома: "

+ "четыре вещественных числа - a, b, c, d ");

init = Console.ReadLine();

a = Convert.ToDouble(init);

init = Console.ReadLine();

b = Convert.ToDouble(init);

init = Console.ReadLine();

c = Convert.ToDouble(init);

init = Console.ReadLine();

d = Convert.ToDouble(init);

Console.WriteLine("Введите три вещественных числа - x1,x2,h"

+ " - границы интервала и шаг");

init = Console.ReadLine();

x1 = Convert.ToDouble(init);

init = Console.ReadLine();

x2 = Convert.ToDouble(init);

init = Console.ReadLine();

h = Convert.ToDouble(init);

//вычисления

double x= x1;

double p =Polinom3(a,b,c,d,x);

int signum = Math.Sign(p);

int signum1 = signum;

while(x<x2)

{

x+=h; p =Polinom3(a,b,c,d,x);

signum1=Math.Sign(p);

if( signum1 != signum)break; //обнаружена смена знака

}

//вывод результатов

if(signum == signum1)

{

mes= "На интервале [{0}, {1}] не обнаружена смена знака полинома!";

Console.WriteLine(mes,x1, x2);

}

else

{

mes= "Обнаружена смена знака полинома! "+

"В точке x1= {0} P(x1) = {1}; В точке x2= {2} P(x2) = {3}";

Console.WriteLine(mes,x-h,Polinom3(a,b,c,d,x-h),x,Polinom3(a,b,c,d,x));

}

}

static double Polinom3(double a, double b, double c, double d, double x)

{

return(((a*x +b)*x+c)*x+d);

}

}

}

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

Модель 80-х годов визуального программирования, управляемого событиями

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

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

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

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

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

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

Рис. 1_1 Интерфейс программы, анализирующей поведение полинома

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

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

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

private void button1_Click(object sender, System.EventArgs e)

{

//объявление переменных

double a,b,c, d; //коэффициенты полинома

double x1, x2; // исходный интервал

double h; //шаг прохождения интервала

string mes; //сообщение о результатах вычислений

// ввод исходных данных

a = Convert.ToDouble(this.textBoxA.Text);

b = Convert.ToDouble(this.textBoxB.Text);

c = Convert.ToDouble(this.textBoxC.Text);

d = Convert.ToDouble(this.textBoxD.Text);

x1 = Convert.ToDouble(this.textBoxX1.Text);

x2 = Convert.ToDouble(this.textBoxX2.Text);

h = Convert.ToDouble(this.textBoxH.Text);

//вычисления

double x= x1;

double p =Polinom3(a,b,c,d,x);

int signum = Math.Sign(p);

int signum1 = signum;

while(x<x2)

{

x+=h; p =Polinom3(a,b,c,d,x);

signum1=Math.Sign(p);

if( signum1 != signum)break; //обнаружена смена знака

}

//вывод результатов

if(signum == signum1)

{

mes= "Не обнаружена смена знака полинома!";

this.textBoxMes.Text = mes;

this.textBoxX.Text = x1.ToString();

this.textBoxPX.Text = Polinom3(a,b,c,d,x1).ToString();

this.textBoxY.Text = x2.ToString();

this.textBoxPY.Text = Polinom3(a,b,c,d,x2).ToString();

}

else

{

mes= "Обнаружена смена знака полинома! ";

this.textBoxMes.Text = mes;

this.textBoxX.Text = (x-h).ToString();

this.textBoxPX.Text = Polinom3(a,b,c,d,x-h).ToString();

this.textBoxY.Text = x.ToString();

this.textBoxPY.Text = Polinom3(a,b,c,d,x).ToString();

}

}

Также как и в консольном приложении в построенный по умолчанию класс Form1 можно добавить функцию Polinom3, вызываемую в обработчике события:

double Polinom3(double a, double b,double c,double d,double x)

{

return(((a*x +b)*x+c)*x+d);

}

Отмечу следующее:

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

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

  • Вся информация, необходимая функции для ее работы, передается через параметры функции.

Задачи

Первые проекты

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

  1. Построить консольное приложение. Дать ему имя, разместить в выбранной директории. Проанализировать созданный программный текст. Познакомиться со средой разработки Visual Studio .Net. Выполнить приложение в пошаговом отладочном режиме.

  2. Построить Windows-приложение. Дать ему имя, разместить в выбранной директории. Проанализировать созданный программный текст. Познакомиться со средой разработки Visual Studio .Net. Выполнить приложение в пошаговом отладочном режиме.

  3. Построить консольное приложение «Здравствуй, Мир!», выводящее на консоль строку приветствия.

  4. Построить Windows-приложение «Здравствуй, Мир!» с командной кнопкой и текстовым окном. Приложение выводит в текстовое окно строку приветствия при нажатии командной кнопки.

  5. Построить консольное приложение «Здравствуй, человек!». Приложение вводит с консоли имя и выводит на консоль строку приветствия, используя введенное имя. Если вводится пустая строка, то выводится текст «Здравствуй, человек!».

  6. Построить Windows-приложение «Здравствуй, человек!» с командной кнопкой и двумя текстовыми окнами. Пользователь вводит имя в первое текстовое окно и при нажатии командной кнопки получает во втором текстовом окне строку приветствия, использующую введенное имя. Если вводится пустая строка, то выводится текст «Здравствуй, человек!».

  7. Построить консольное приложение «Здравствуйте, люди!». Приложение вводит с консоли имя и выводит на консоль строку приветствия, используя введенное имя. Вводу имени предшествует приглашение к вводу «Введите имя».

  8. Построить Windows-приложение «Здравствуйте, люди!» с командной кнопкой и двумя текстовыми окнами. Пользователь вводит имя в первое текстовое окно и при нажатии командной кнопки получает во втором текстовом окне строку приветствия, использующую введенное имя. С каждым текстовым окном связывается окно метки, в котором дается описание назначения текстового окна.

  9. Построить циклическое консольное приложение «Здравствуй, человек!». Приложение вводит с консоли имя и выводит на консоль строку приветствия, используя введенное имя. Вводу имени предшествует приглашение к вводу «Введите имя». После приветствия на консоль выводится запрос на продолжение работы «Продолжить работу? (да, нет)». В зависимости от введенного ответа повторяется приветствие или приложение заканчивает работу.

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

do

{

…

}while((answer=="Да") || (answer=="да" ));

Здесь answer переменная, содержащая ответ пользователя на предложение продолжения работы.

Встроенные типы данных. Ввод-вывод данных.

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

  1. Построить циклическое консольное приложение «Целочисленные типы». Приложение поочередно вводит с консоли значения целочисленных типов: sbyte, byte, short, ushort, int, uint, long, ulong. Вводу значения предшествует приглашение к вводу. После завершения ввода приложения выводит все введенные значения с указанием их типа. Проанализировать, что происходит при вводе значений, не соответствующих требуемому типу или выходящих за пределы интервала возможных значений типа.

  2. Построить Windows-приложение «Целочисленные типы» с 16-ю помеченными текстовыми окнами и двумя командными кнопками Пользователь вводит значения целочисленных типов: sbyte, byte, short, ushort, int, uint, long, ulong в первые 8 окон. По нажатию командной кнопки «Ввод значений» данные из текстовых окно становятся значениями переменных соответствующих типов. По нажатию командной кнопки «Вывод значений» значения переменных соответствующих типов передаются в текстовые окна, предназначенные для вывода значений. Проанализировать, что происходит при вводе значений, не соответствующих требуемому типу или выходящих за пределы интервала возможных значений типа.

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

  4. Построить Windows-приложение «Вещественные типы» с 4-мя помеченными текстовыми окнами и двумя командными кнопками Пользователь вводит значения вещественных типов: float, double в первые 2 окна. По нажатию командной кнопки «Ввод значений» данные из текстовых окно становятся значениями переменных соответствующих типов. По нажатию командной кнопки «Вывод значений» значения переменных соответствующих типов передаются в текстовые окна, предназначенные для вывода значений. Проанализировать, что происходит при вводе значений, не соответствующих требуемому типу или выходящих за пределы интервала возможных значений типа.

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

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

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

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

  9. Построить циклическое консольное меню-приложение «Выбор». Приложение выводит на консоль нумерованные пункты меню, предлагая затем пользователю задать номер выбранного им пункта меню. При вводе пользователем соответствующего номера начинает выполняться выбранный пункт меню. В данной задаче команды меню определяют тип значений, вводимых и выводимых на консоль (смотри задачи 1.10 – 1.18).

  10. Построить Windows-приложение «Выбор». В одно из текстовых окон пользователь вводит тип переменной, в другое – значение. По нажатию командной кнопки «Ввод значений» данные из текстового окна становятся значением переменной, тип которой задан в первом текстовом окне. По нажатию командной кнопки «Вывод значений» значение переменной передается в текстовое окно, предназначенное для вывода значений.

Выражения. Оптимизация выражений. Память или время.

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

Память и время – два основных ресурса. В распоряжении программиста при решении задач есть два основных ресурса – это память компьютера и его быстродействие. На первых порах кажется, что оба эти ресурса безграничны и потому можно не беспокоиться о том, как тратятся эти ресурсы. Эти представления иллюзорны. Многие задачи, возникающие на практике, таковы, что имеющихся ресурсов не хватает и требуется жесткая их экономия. Вот два простых примера. Если в программе есть трехмерный массив A: double[,,]A = new double[n,n,n],то уже при n =1000 оперативной памяти современных компьютеров не хватит для хранения элементов этого массива. Если приходится решать задачу, подобную задаче о «ханойской башне», где время решения задачи T = O(2n), то уже при n = 64 никакого быстродействия всех современных компьютеров не хватит для решения этой задачи в сколь либо допустимые сроки. Программист обязан уметь оценивать объем ресурсов, требуемых программе. Говоря о ресурсах, требуемых программе P, часто используют термины – временная и емкостная сложность – T(P) и V(P). Выражения представляют хорошую начальную базу для оценивания этих характеристик.

Характеристики T(P) и V(P) обычно взаимосвязаны. Увеличивая расходы памяти, можно уменьшить время решения задачи, или, выбирая другое решение, сократить расходы памяти, увеличивая время работы. Одна из реальных задач, стоящих перед профессиональным программистом – это нахождение нужного компромисса между памятью и временем. Помните:

«Выбора тяжко бремя – память или время!»

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

Именованные константы. Еще один важный урок, который должны давать задачи этого раздела, это введение именованных констант. Помните:

«Каждой константе имя давайте,

Числа без имени из программ изгоняйте!»

Исключением могут быть простые константы – 0, 1, 2, 3. Если, как это часто бывает, изменяется значение константы, то это изменение должно делаться только в одном месте, там, где эта константа определяется.

  1. Построить циклическое консольное меню-приложение «Арифметические операции». Команды меню задают арифметические операции, допустимые в выражениях языка C#. При выборе пункта меню пользователь получает приглашение к вводу одного или двух значений в зависимости от выбранного пункта меню, затем над значениями выполняется соответствующая операция, и ее результат выводится на консоль.

  2. Построить Windows-приложение «Арифметические операции». В одно или два текстовых окна пользователь вводит значения. По нажатию командной кнопки, задающей тип арифметической операции, над введенными значениями выполняется соответствующая операция, и ее результат выводится в текстовое окно, предназначенное для вывода значений.

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

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

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

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

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

  8. Построить Windows-приложение «Класс Math». В одно или два текстовых окна пользователь вводит значения. По нажатию командной кнопки, задающей функцию класса Math, к введенным значениям применяется соответствующая функция, и ее результат выводится в текстовое окно, предназначенное для вывода значений.

  9. (*) Построить Windows-приложение «Стандартный калькулятор», аналогичный Windows калькулятору ­– приложению Calculator в режиме Standard.

  10. (**) Построить Windows-приложение «Научный калькулятор», аналогичный Windows калькулятору ­– приложению Calculator в режиме Scientific.

  11. Построить консольное приложение «Expression1». Приложение вычисляет значение x и выводит его на консоль, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. Оцените время вычисления выражения в условных единицах (уе), исходя из следующих предположений: присваивание – 1 уе, операции сдвига –2 уе, сложение, вычитание – 3 уе, умножение – 5 уе, деление – 7 уе, вызов стандартной функции – 13 уе. Обоснуйте корректность вычисления значения выражения? Поочередно изменяйте значения числовых констант, участвующих в выражении, например замените 527 на 526, 85. Если изменения требуется вносить в нескольких местах программного текста, то подумайте о более разумном способе записи этого выражения.

  12. Построить Windows-приложение «Expression1». Приложение вычисляет значение x и выводит его в текстовое окно, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. Оцените время вычисления выражения в условных единицах (см. 1.30). Обоснуйте корректность вычисления значения выражения? Поочередно изменяйте значения числовых констант, участвующих в выражении, например замените 527 на 526, 85. Если изменения требуется вносить в нескольких местах программного текста, то подумайте о более разумном способе записи этого выражения.

  13. Построить консольное приложение «Expression2». Приложение вычисляет значение x и выводит его на консоль, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. Оцените время вычисления выражения в условных единицах (см. 1.30). Обоснуйте корректность вычисления значения выражения?

  14. Поочередно изменяйте значения числовых констант, участвующих в выражении, например замените 527 на 526, 85. Если изменения требуется вносить в нескольких местах программного текста, то подумайте о более разумном способе записи этого выражения.

  15. Построить Windows-приложение «Expression2». Приложение вычисляет значение x и выводит его в текстовое окно, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. Оцените время вычисления выражения в условных единицах (см. 1.30). Обоснуйте корректность вычисления значения выражения? Поочередно изменяйте значения числовых констант, участвующих в выражении, например замените 527 на 526, 85. Если изменения требуется вносить в нескольких местах программного текста, то подумайте о более разумном способе записи этого выражения.

  16. Построить консольное приложение «Expression3». Приложение вычисляет значение x и выводит его на консоль, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. Оцените время вычисления выражения в условных единицах (см. 1.30). Обоснуйте корректность вычисления значения выражения? Поочередно изменяйте значения числовых констант, участвующих в выражении, например замените 527 на 526, 85. Если изменения требуется вносить в нескольких местах программного текста, то подумайте о более разумном способе записи этого выражения.

  17. Построить Windows-приложение «Expression3». Приложение вычисляет значение x и выводит его в текстовое окно, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. Оцените время вычисления выражения в условных единицах (см. 1.30). Обоснуйте корректность вычисления значения выражения? Поочередно изменяйте значения числовых констант, участвующих в выражении, например замените 527 на 526, 85. Если изменения требуется вносить в нескольких местах программного текста, то подумайте о более разумном способе записи этого выражения.

  18. Построить консольное приложение «Expression4». Приложение вычисляет значение x и выводит его на консоль, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. В вычисляемом выражении m, n, p, a, b, c, d, e – это имена констант.

  19. Построить Windows-приложение «Expression4». Приложение вычисляет значение x и выводит его в текстовое окно, где Вычисление выражения построить так, чтобы минимизировать время его вычисления. В вычисляемом выражении m, n, p, a, b, c, d, e – это имена переменных, значения которых задаются в соответствующих текстовых окнах.

  20. (**) Построить консольное приложение «Expression5». Приложение вычисляет значение x и время T в миллисекундах, требуемое для n-кратного (n =100000) его вычисления, где Для вычисления времени использовать возможности класса DateTime, его свойства Now, Hour и другие. Вычисление выражения построить разными способами. Проанализировать, как это влияет на эффективность вычислений по времени.

  21. (**) Построить Windows-приложение «Expression5». Приложение вычисляет значение x и время T в миллисекундах, требуемое для n-кратного (n =100000) его вычисления, где Для вычисления времени использовать возможности класса DateTime, его свойства Now, Hour и другие. Вычисление выражения построить разными способами. Проанализировать, как это влияет на эффективность вычислений по времени.

  22. Построить Windows-приложение «Круг». Дано: r – радиус круга, alpha – центральный угол в градусах. Вычислить: диаметр, длину окружности, площадь круга, Площадь сектора, площадь сегмента и длину хорды, определяемую центральным углом.

  23. Построить Windows-приложение «Квадрат». Дано: сторона квадрата – a. Точки B и C расположены на сторонах квадрата, примыкающих к вершине квадрата A. Расстояние AB = b, AC = c. Вычислить: площадь четырехугольника OBAC, где О – центр квадрата. Вычислить OB, OC и углы четырехугольника.

  24. Построить Windows-приложение «Треугольник». Дано: стороны треугольника a,b,c. Вычислить остальные элементы треугольника.

Преобразования в выражениях. Семантика присваивания.

  1. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что выражение a ● b (здесь ● – символ применяемой операции) не требует преобразования типов операндов.

  2. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что выражение a ● b (здесь ● – символ применяемой операции) требует преобразования типов операндов, но все преобразования типов неявные и выполняются автоматически.

  3. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что выражение a ● b (здесь ● – символ применяемой операции) требует явного преобразования типов операндов.

  4. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что выражение a ● b (здесь ● – символ применяемой операции) требует явного преобразования типов операндов. Рассмотрите только такие преобразования, которые можно выполнить любым из трех доступных способов преобразования типов: методами класса Convert, методами Parse, приведением к типу – кастингом.

  5. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что выражение a ● b (здесь ● – символ применяемой операции) требует явного преобразования типов операндов. Рассмотрите только такие преобразования, которые не допускают приведения к типу – кастинг.

  6. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что выражение a ● b (здесь ● – символ применяемой операции) требует явного преобразования типов операндов. Рассмотрите только такие преобразования, которые можно выполнить только с помощью методов класса Convert.

  7. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что тип T выражения a ● b (здесь ● – символ применяемой операции) T = T1 = T2.

  8. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что тип T выражения a ● b (здесь ● – символ применяемой операции) T = T1 != T2.

  9. Пусть a и b – переменные типов T1 и T2 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1 и T2 такие, что тип T выражения a ● b (здесь ● – символ применяемой операции) T != T1 != T2.

  10. Пусть a, b и c– переменные типов T1, T2 и T3 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1, T2 и T3 такие, что при присваивании c= a ● b (здесь ● – символ применяемой операции) не возникает необходимости преобразования типа T выражения правой части к типу T3.

  11. Пусть a, b и c– переменные типов T1, T2 и T3 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1, T2 и T3 такие, что при присваивании c= a ● b (здесь ● – символ применяемой операции) возникает необходимость преобразования типа T выражения правой части к типу T3. Рассмотрите только неявные преобразования, выполняемые автоматически.

  12. Пусть a, b и c– переменные типов T1, T2 и T3 соответственно. Постройте приложение (консольное или Windows), в котором для каждой из допустимых в языке C# операций задайте все возможные комбинации типов T1, T2 и T3 такие, что при присваивании c= a ● b (здесь ● – символ применяемой операции) возникает необходимость преобразования типа T выражения правой части к типу T3. Рассмотрите только явные преобразования. Покажите, в каких ситуациях применим тот или иной способ преобразования типов – методы класса Convert, методы Parse, приведение к типу.

Альтернатива и разбор случаев

  1. Постройте консольное и Windows-приложение, которое по заданным коэффициентам a, b, c находит корни квадратного уравнения.

  2. Постройте консольное и Windows-приложение, которое по заданному значению аргумента x вычисляет значение функции y=F(x), где функция F(x) задана соотношением: Постройте консольное и Windows-приложение, которое по заданному значению аргумента x вычисляет значение функции y=F(x), где функция F(x) задана графиком:

  3. Постройте консольное и Windows-приложение, которое по заданному значению аргумента x вычисляет значение функции y=F(x), где функция F(x) задана графиком:

  4. Постройте консольное и Windows-приложение, которое по заданному значению аргумента x вычисляет значение функции y=F(x), где периодическая функция F(x) задана графиком:

  5. Постройте консольное и Windows-приложение, которое по заданным координатам x и y определяет, принадлежит ли точка (x, y) одной из 6 дорог (a, b, c, d, e, f), показанных на графике. Если точка принадлежит дороге, то укажите какой именно дороге, если принадлежит двум дорогам, то и этот факт следует отразить в результирующем сообщении.

  6. Дана точка A с координатами (x, y) и два прямоугольника Q1 и Q2 со сторонами, параллельными осям координат. Каждый из прямоугольников задается парой точек Q1(p1, p2), Q2(p3, p4), определяющих левый нижний и правый верхний углы прямоугольника. Постройте консольное и Windows-приложение, которое определяет, принадлежит ли точка A(x, y) хотя бы одному из прямоугольников Q1 и Q2. Если точка принадлежит прямоугольнику, то следует сообщить, какому именно прямоугольнику, если принадлежит двум прямоугольникам, то и этот факт должен быть отражен в результирующем сообщении. Если точка принадлежит границе прямоугольника, то и это должно быть отображено в сообщении.

  7. Дана точка A с координатами (x, y) и мишень – 10 концентрических кругов с центром в начале координат и радиусами R1, R2 … R10. Постройте консольное и Windows-приложение, которое определяет количество выбитых очков. Предполагается, как обычно, что за попадание точки в круг самого малого радиуса начисляется 10 очков и так далее до одного очка. За попадание в «молоко» очки не начисляются.

  8. (*) Дана точка A с координатами (x, y) и треугольник, заданный своими вершинами – точками Q1(x1, y1), Q2(x2, y2) и Q3(x3, y3). Постройте консольное и Windows-приложение, которое определяет, принадлежит ли точка A треугольнику (находится внутри его или на его границах).

  9. Дан текст T. Постройте консольное и Windows-приложение, которое проводит частотный анализ, определяя частоту вхождения букв А, Б, … Я (больших и малых) в текст T.

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

  11. Студент, приходящий на экзамен, характеризуется тремя булевскими переменными P1, P2 и P3. Переменная P1 имеет значение true, если студент знает определения, и false в противном случае. Переменная P2 имеет значение true, если студент умеет доказывать теоремы, и false в противном случае. Переменная P3 имеет значение true, если студент умеет решать задачи, и false в противном случае. Постройте консольное и Windows-приложение «Строгий экзаменатор», в котором экзаменатор руководствуется следующим алгоритмом: он спрашивает определение и ставит оценку «неуд», в случае его незнания. Студенту, знающему определение, предлагается доказать теорему, в случае неуспеха ставится оценка «уд». Студенту, знающему определения и умеющему доказывать теоремы, предлагается решить задачу, в случае неуспеха ставится оценка «хор», в случае успеха – «отл».

  12. Студент, приходящий на экзамен, характеризуется тремя булевскими переменными P1, P2 и P3. Переменная P1 имеет значение true, если студент знает определения, и false в противном случае. Переменная P2 имеет значение true, если студент умеет доказывать теоремы, и false в противном случае. Переменная P3 имеет значение true, если студент умеет решать задачи, и false в противном случае. Постройте консольное и Windows-приложение «Добрый экзаменатор», в котором экзаменатор руководствуется следующим алгоритмом: он предлагает решить задачу и в случае успеха ставит оценку – «отл». Студенту, не умеющему решать задачи, предлагается доказать теорему, в случае успеха ставится оценка «хор». Студенту, не умеющему решать задачи и не умеющему доказывать теоремы, предлагается сформулировать определение и в случае его незнания ставится оценка «неуд», в случае успеха ставится оценка «уд».

Вычисление сумм, произведений и рекуррентные соотношения.

Вычисление конечных сумм и произведений – это наиболее часто встречающийся тип элементарных задач, шаблон решения которых должен быть заучен, как 2*2. Какова бы не была сложность выражений, стоящих под знаком суммы, задачу всегда можно записать в виде:

и применить для ее решения следующий шаблон:

S=0;

for(int k=1; k<=n; k++)

{

//Вычислить текущий член суммы ak

…

S+=ak;

}

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

Init;

for(int k=1; k<=n; k++)

{

//Вычислить текущий член суммы ak

…

S+=ak;

}

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

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

  • Чистка цикла. Все вычисления, не зависящие от k, должны быть вынесены из цикла (в раздел Init).

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

Рассмотрим пример. Пусть необходимо вычислить сумму:

Тогда в соответствии с шаблоном

Можно построить рекуррентную формулу для ak, поскольку каждое следующее значение равно предыдущему значению, умноженному на x и деленному на k. Вычисление суммы задает следующий фрагмент программы:

int S =0;

int ak=1;

for(int k=0; k<=n; k++)

{

S+=ak;

//Вычислить текущий член суммы ak

ak *=x/k;

}

Большинство задач этого раздела соответствуют этому шаблону. Рекуррентную формулу чаще всего можно получить, записав выражение для ak и ak-1, вычислив затем их отношение. В некоторых задачах (они отмечены звездочкой) получение рекуррентной формулы может требовать больших усилий.

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

  1. Дано натуральное число n. Вычислить сумму первых n членов расходящегося гармонического ряда:

  2. Дано натуральное число nmax и вещественное число b. Найти, если оно существует, такое наименьшее n, меньшее nmax, что: Если сумма nmax членов гармонического ряда меньше b, то необходимо выдать соответствующее сообщение.

  3. Дано натуральное число n. Вычислить сумму первых n членов ряда: При суммировании исключается каждый третий член.

  4. Дано натуральное число n. Вычислить сумму первых 2n членов ряда: Вычислить эту сумму четырьмя разными способами: последовательно слева направо, последовательно справа налево, слева направо, вычисляя вначале положительные члены ряда, затем отрицательные, справа налево, вычисляя вначале положительные члены ряда, затем отрицательные. Сравните результаты вычислений. Чем объясняется различие в последних цифрах при больших n? Как влияет на результат использование типов float или double для переменных, задающих суммы и текущий член при суммировании?

  5. Дано натуральное число n. Вычислить сумму первых 2n членов ряда:

  6. Дано натуральное число n. Вычислить произведение первых n членов ряда:

  7. Даны натуральные числа n и k (n>=k). Вычислить биномиальный коэффициент Cnk :

  8. Даны натуральные числа n и m (n>=m). Вычислить сумму биномиальных коэффициентов: Следует напомнить, что определения функций суммы и произведения предполагают:

  9. Дан массив B размерности n*m и массив C размерности m*n. Вычислить сумму диагональных элементов матрицы A = B*C:

  10. Дан массив B размерности n*m и массив C размерности m*n. Вычислить произведение диагональных элементов матрицы A = B*C:

  11. Даны натуральные числа n и m, вещественное x. Вычислить:

Рекуррентные вычисления

  1. Вычислить Fn - число Фибоначчи с номером n, где F1 = 1; F2 = 1; Fk = Fk-1 + Fk-2 для k>2.

  2. Дано натуральное число n и вещественные числа b и d. Вычислить сумму членов арифметической прогрессии: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, чтобы его вычисление требовало ровно одного сложения

  3. Дано натуральное число n и вещественные числа b и d. Вычислить сумму членов геометрической прогрессии: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, чтобы его вычисление требовало ровно одного умножения.

  4. Дано натуральное число n. Вычислить: где

  5. Даны натуральные числа n и m (50<m<n). Вычислить: где

  6. Даны натуральные числа n и m (50<m<n). Вычислить: где

  7. Дано натуральное число n и вещественное число x. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, чтобы его вычисление выполнялось за время, равное 12 уе. (см. задачу 1.30). Сравните вычисленное значение S со значением ex. Вычислите разность | S – ex| при различных значениях n и x.

  8. Дано натуральное число n и вещественное число x. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, чтобы его вычисление выполнялось за время, равное 27 уе. (см. задачу 1.30). Сравните вычисленное значение S со значением sin(x). Вычислите разность | S – sin(x)| при различных значениях n и x.

  9. Дано натуральное число n и вещественное число x такое, что |x| <1. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, минимизируя время его вычисления. Сравните вычисленное значение S со значением arcsin(x). Вычислите разность | S – arcsin(x)| при различных значениях n и x.

  10. Дано натуральное число n и вещественное число x. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, чтобы его вычисление выполнялось за время, равное 27 уе. (см. задачу 1.30). Сравните вычисленное значение S со значением cos(x). Вычислите разность | S – cos(x)| при различных значениях n и x.

  11. Дано натуральное число n и вещественное число x такое, что |x| <1. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, минимизируя время его вычисления. Сравните вычисленное значение S со значением arccos(x). Вычислите разность | S – arccos(x)| при различных значениях n и x.

  12. Дано натуральное число n и вещественное число x >0. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы. Минимизируйте время его вычисления в условных единицах. Сравните вычисленное значение S со значением ln(x). Вычислите разность | S – ln(x)| при различных значениях n и x.

  13. (**) Даны натуральные числа n и m и вещественное число x такое, что |x| < π/2. Вычислить: где Bi определяются следующим соотношением: Предварительно следует записать рекуррентные соотношения, как для получения чисел Bi, так и для вычисления S. Сравните вычисленное значение S со значением tg(x). Вычислите разность | S – tg(x)| при различных значениях n и x.

  14. (*) Даны натуральные числа n и m и вещественное число x такое, что |x| < π/2. Вычислить: Сравните вычисленное значение S со значением tg(x). Вычислите разность | S – tg(x)| при различных значениях n и x.

  15. Дано натуральное число n и вещественное число x . Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, минимизируя время его вычисления. Сравните вычисленное значение S со значением arctg(x). Вычислите разность | S – arctg(x)| при различных значениях n и x.

  16. (**) Даны натуральные числа n и m и вещественное число x такое, что |x| < π. Вычислить: где Bi определяются следующим соотношением: Предварительно следует записать рекуррентные соотношения, как для получения чисел Bi, так и для вычисления S. Сравните вычисленное значение S со значением ctg(x). Вычислите разность | S – ctg(x)| при различных значениях n и x.

  17. Дано натуральное число n и вещественное число x . Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, минимизируя время его вычисления. Сравните вычисленное значение S со значением arcctg(x). Вычислите разность | S – arcctg(x)| при различных значениях n и x.

  18. (**) Даны натуральные числа n и m и вещественное число x такое, что |x| < π/2. Вычислить: где Ei определяются следующим соотношением: Предварительно следует записать рекуррентные соотношения, как для получения чисел Ei, так и для вычисления S. Сравните вычисленное значение S со значением sc(x). Вычислите разность | S – sc(x)| при различных значениях n и x.

  19. Дано натуральное число n и вещественное число x. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, минимизируя время его вычисления. Сравните вычисленное значение S со значением sh(x). Вычислите разность | S – sh(x)| при различных значениях n и x.

  20. Дано натуральное число n и вещественное число x. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, минимизируя время его вычисления. Сравните вычисленное значение S со значением ch(x). Вычислите разность | S – ch(x)| при различных значениях n и x.

  21. Дано натуральное число n и вещественное число x такое, что |x| <1. Вычислить: Предварительно следует записать рекуррентное соотношение для текущего члена суммы, минимизируя время его вычисления. Сравните вычисленное значение S со значением Arcsh(x). Вычислите разность | S – Arcsh(x)| при различных значениях n и x.

Бесконечность и компьютеры. Вычисления с точностью ε

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

Мир компьютеров – это конечный мир, хотя в нем и присутствует стремление к бесконечности. Множества, с которыми приходится оперировать в мире компьютера, всегда конечны. Тип целых чисел в языках программирования – int – всегда задает конечное множество целых из некоторого фиксированного диапазона. В библиотеке FCL это наглядно подтверждается самими именами целочисленных типов System.Int16, System.Int32, System.Int64. Типы вещественных чисел – double, float – задают конечные множества. Это достигается не только тем, что диапазон задания вещественных чисел ограничен, но и ограничением числа значащих цифр, задающих вещественное число. Поэтому для вещественных чисел компьютера всегда можно указать такие два числа, между которыми нет никаких других чисел. Иррациональности компьютер не знает, – число π всегда задается конечным числом цифр.

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

По определению число A является пределом числовой последовательности, если для любого сколь угодно малого числа ε существует такой номер N, зависящий от ε, что для всех n, больших N, числа an находятся в ε-окрестности числа A. Это определение дает основу для вычисления значения предела A. Понятно, что получить точное значение A во многих случаях принципиально невозможно, – его можно вычислить лишь с некоторой точностью и тоже не сколь угодно малой, поскольку, как уже говорилось, есть понятие «машинного нуля» - минимального числа, все значения меньше которого воспринимаются как нуль. В задаче 1.97 требуется вычислить значение числа π как предел числовой последовательности. Оставаясь в рамках стандартных множеств чисел (double, float) принципиально невозможно получить точное значение этого числа, поскольку в этих множествах нет иррациональных чисел с бесконечным числом цифр. Но можно получить значение этого числа с некоторой точностью. Когда два соседних члена последовательности – an и an+1 – начинают отличаться на величину, по модулю меньшую чем δ, то можно полагать, что оба члена последовательности попали в ε-окрестность числа A и an+1 можно принять за приближенной значение числа A. Это рассуждение верно только при условии, что последовательность действительно имеет предел. В противном случае этот прием может привести к ошибочным выводам. Например, последовательность, элементы которой равны 1, если индекс элемента делится на 3, и равны 2, если индекс не делится на 3. Очевидно, что у этой последовательности предела нет, хотя существуют два полностью совпадающих соседних членов последовательности.

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

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

Вот возможный шаблон ее решения:

public double f(double x)

{

double S=0,ak=1, eps=1e-8;

while(Math.Abs(ak) >eps)

{

//Вычислить ak

S+=ak;

}

return(S);

}

При применении этого шаблона следует:

  • Получить при возможности рекуррентную формулу, используя для вычисления нового значения ak ранее вычисленные значения.

  • Использовать по возможности свойства функции f(x) для ускорения сходимости ak к нулю, например привести x к минимально возможному диапазону для периодических функций.

  • Помнить, что данный шаблон применим только тогда, когда ряд является сходящимся.

  • Понимать, что выполнение условия (|ak| < eps ) еще не означает, что значение функции вычислено с точностью eps. Строго говоря, необходимо иметь оценку остаточного члена ряда. На практике этим обстоятельством зачастую можно пренебрегать, уменьшая при необходимости eps и достигая тем самым нужной точности вычисления f(x).

Во всех задачах этого раздела задается точность вычислений ε – малое вещественное число. Обычно, если требуется получить результат с точностью до 5-6 значащих цифр, то ε задается константой 10-8- 10-9 (1e-8 – 1e-9).

  1. Вычислить с заданной точностью значение числа π, используя следующее разложение в ряд: Предварительно следует записать рекуррентное соотношение для текущего члена суммы. Минимизируйте время его вычисления в условных единицах. Сравните вычисленное значение π со стандартным значением PI, возвращаемым классом Math. Для разных значений ε вычислите n – число членов суммы, требуемых для достижения заданной точности.

  2. Вычислить с заданной точностью значение числа π, используя следующее разложение в ряд: Предварительно следует записать рекуррентное соотношение для текущего члена суммы. Минимизируйте время его вычисления в условных единицах. Сравните вычисленное значение π со стандартным значением PI, возвращаемым классом Math. Для разных значений ε вычислите n – число членов суммы, требуемых для достижения заданной точности.

  3. Вычислить с заданной точностью значение числа π, используя следующее разложение в ряд: Предварительно следует записать рекуррентное соотношение для текущего члена суммы. Минимизируйте время его вычисления в условных единицах. Сравните вычисленное значение π со стандартным значением PI, возвращаемым классом Math. Для разных значений ε вычислите n – число членов суммы, требуемых для достижения заданной точности.

  4. Вычислить с заданной точностью значение числа e, используя следующее разложение в ряд: Предварительно следует записать рекуррентное соотношение для текущего члена суммы. Минимизируйте время его вычисления в условных единицах. Сравните вычисленное значение e со стандартным значением E, возвращаемым классом Math. Для разных значений ε вычислите n – число членов суммы, требуемых для достижения заданной точности.

  5. Пусть Fn и Fn+1 – два соседних числа Фибоначчи (см. задачу 1.76). Найти с заданной точностью предел отношения (Fn/Fn+1) при n→∞. Сравнить этот предел с «золотым сечением» - числом x. Напомню, золотое сечение строится следующим образом. Возьмем отрезок единичной длины и разделим его на две неравные части – большую x и меньшую y=1-x. Сечение называется «золотым», если отношение целого к большей части равно отношению большей части к меньшей: x/(1-x) = 1/x.

  6. Даны два положительных числа b и d. Пусть: Вычислить с заданной точностью пределы bn, dn, dn-bn.

  7. Пусть x и y=1-x задают золотое сечение отрезка единичной длины (см. задачу 1.102). Пусть задано число α такое, что α >0 и α<1. Вычислить с заданной точностью предел последовательности bn, где

  8. Дано вещественное число x. Вычислить с заданной точностью ex: Указание: для ускорения вычислений используйте разложение в ряд только для дробной части числа x. Используйте умножение и константу e для вычисления en, где n – это целая часть числа x.

  9. Дано вещественное число x. Вычислить с заданной точностью sin(x): Указание: для ускорения вычислений используйте разложение в ряд только для приведенного значения числа x. Помните, что sin(x) – это периодическая функция, так что всегда можно привести x к интервалу [-π, π].

  10. Дано вещественное число x такое, что |x| <1. Вычислить с заданной точностью arcsin(x):

  11. Дано вещественное число x. Вычислить с заданной точностью cos(x): Указание: для ускорения вычислений используйте разложение в ряд только для приведенного значения числа x. Помните, что cos(x) – это периодическая функция, так что всегда можно привести x к интервалу [-π, π].

  12. Дано вещественное число x такое, что |x| <1. Вычислить с заданной точностью arccos(x):

  13. Дано вещественное число x >0. Вычислить с заданной точностью ln(x):

  14. Дано вещественное число x. Вычислить с заданной точностью tg(x): где Bi определяются следующим соотношением: Указание: используйте разложение в ряд только для приведенного значения числа x. Помните, что tg(x) – это периодическая функция, так что всегда можно привести x к интервалу [-π/2, π/2].

  15. Дано вещественное число x . Вычислить с заданной точностью arctg(x):

  16. (**) Дано вещественное число x. Вычислить с заданной точностью ctg(x): где Bi определяются следующим соотношением: Указание: используйте разложение в ряд только для приведенного значения числа x. Помните, что сtg(x) – это периодическая функция, так что всегда можно привести x к интервалу [-π/2, π/2].

  17. Дано вещественное число x . Вычислить с заданной точностью arcсtg(x):

  18. (**) Дано вещественное число x. Вычислить с заданной точностью sc(x): где Ei определяются следующим соотношением: Указание: используйте разложение в ряд только для приведенного значения числа x. Помните, что sc(x) – это периодическая функция, так что всегда можно привести x к интервалу [-π, π].

  19. Дано вещественное число x. Вычислить с заданной точностью sh(x): Указание: гиперболический синус sh(x) не является периодической функцией, поэтому никакого приведения x выполнять не следует.

  20. Дано вещественное число x. Вычислить с заданной точностью ch(x):

  21. Дано вещественное число x. Вычислить с заданной точностью Arcsh(x):

Проекты

  1. (*) Постройте класс MyMath, имеющий те же методы, что и класс Math библиотеки FCL.

  2. (**) Постройте Windows-приложение, позволяющее сравнить результаты вычислений методов класса Math и MyMath по точности и времени вычислений.

Слово, число, рисунок, музыка,– величайшие изобретения человечества.