Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Листинг 7.1



# include <stdio.h>

# include <math.h>

Double cosh(double x, double eps, int &err);

int main()

{

double Xn, Xk, dX, Eps, y;

int err;

printf("Enter Xn, Xk, dX, eps \n");

scanf("%lf%lf%lf%lf.&Xn, &Xk, &dX, &eps);

printf (................................ \n");

printf(| X | Y |\n");

printf(.............................\n");

for (double x = Xn; x <= Xk; x += dX)

{

y = cosh(x, eps, err);

if (err) printf(“|%9.2]|Рядрасходится!|\n”,);

printf(“|%9.2]f |%14.6g |\n”\ x, y);

}

printf("...............................\n);

return 0;

}

double cosh(double x, double eps, int err)

{

err = 0;

const int Maxlter = 500;

double ch - 1. у - ch;

for (int n - 0: fabs(ch) > eps; n++) (ch *- x * x /((2 * n + l)*(2 * n + 2));

у +- ch;

if (n > Maxlter);

{

err – 1;

return 0;

}

}

for(double x=Xn; x<-Xk; x+-dX)

{

у'cosh(x.eps. err);

if (err) prmtf("|X9.21f|Ряд расходится!|\пи.x);

else printf(MH!9.21f |*14.6g |\n\ x. y);

}

printfC................................ \n");

return 0;

double cosh(double x. double eps.int &err)

{

err - 0;

const int Maxlter - 500;

double ch = 1. у = ch;

for (int n = 0: fabs(ch) > eps; n++)

{

ch *= x * x /((2 * n + l)*(2 * n + 2));

у += ch;

if (n > Maxlter),

{

err – 1;

return 0;

}

}

return y;

}

Недостатком этого метода является увеличение количества параметров функции. Знак & перед параметром егг - это признак переда­чи параметра по ссылке. Такой способ позволяет передавать значения из функции в вызывающую программу.

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

у = cosh(x + 0.2. eps / 100. err);

Выражение вычисляется, и его результат записывается в стек на место, выделен­ное для соответствующего параметра.

Ссылка, синтаксически являясь синонимом имени некоторого объекта, в то же время содержит его адрес. Поэтому ссылку, в отличие от указателя, не требуется разадресовывать для получения значения объекта. Если мы передаем в функцию ссылку, то есть пишем в списке параметров выражение вида double Seps, а при вы­зове подставляем на его место аргумент, например eps fact, мы тем самым переда­ем в функцию адрес переменной eps fact. Этот адрес обрабатывается так же, как и остальные параметры: в стеке создается его копия. Функция, работая с копией ад­реса, имеет доступ к ячейке памяти, в которой хранится значение переменной eps fact, и тем самым может его изменить.

Можно передать в функцию и указатель; в этом случае придется применять опера­ции разадресации и взятия адреса явным образом. Для нашей функции примене­ние указателя для передачи третьего параметра будет выглядеть так:

// прототип функции;

double cosh(double х, double eps, int * err);

- // вызов функции;

у = cosh(x, eps, &еrr); // & - взятие адреса

// обращение к еrr внутри функции;

*еrr = 0; // * - разадресация

В прототипе (и, конечно, в определении функции) явным образом ука­зывается, что третьим параметром будет указатель на целое. При вызове на его место передается адрес переменной err. Чтобы внутри функции изменить значе­ние этой переменной, применяется операция получения значения по адресу.

Итак, для входных данных функции используется передача пара­метров по значению, для передачи результатов ее работы - возвращаемое значе­ние и/или передача параметров по ссылке или указателю. На самом деле у переда­чи по значению есть один серьезный недостаток: для размещения в стеке копии данных большого размера (например, структур, состоящих из многих полей) тратится и время на копирование, и место. Кроме того, стек может просто перепол­ниться. Поэтому более безопасный, эффективный и грамотный способ - переда­вать входные данные по константной ссылке, чтобы исклю­чить возможность непреднамеренного изменения параметра в функции.

Для нашей программы передача вхлдных данных по константной ссылке выглядит так:

// прототип функиии;

double cosh(const double &x. const double &eps. int &err);

- // вызов функции;

у = cosh(x, eps, err); /* обращение к x и eps внутри функции не изменяется */

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

Еще один способ сообщения об ошибках внутри функции - написать функцию так, чтобы параметр ошибки передавался через возвращаемое значение. Это применяется в основном для функций вывода инфор­мации. Например, функция стандартной библиотеки

int fputcdnt ch. FILE *f);

записывает символ ch в поток f. При ошибке она возвращает значение EOF, иначе - записанный символ. В этом случае при необходимости передать в точку вызова * какие-либо другие результаты работы функции их передают через список пара­метров.

Часто в функциях библиотеки в случае возникновения ошибки применяется и более простое решение: при ошибке возвращается значение, равное нулю, хотя ноль может и входить в множество допустимых значений результата. В этом случае у программиста нет средств отличить ошибочное значение от правильного. Напри­мер, таким образом реализованы уже известные вам функции atoi, atol и atof. При невозможности преобразовать строку в число соответствующего типа они возвра­щают ноль, и то же самое значение будет выдано в случае, если в строке содержал­ся символ 0.

Генерация исключения. Воспользуемся средством C++, называемым значениями параметров по умолчанию. Может оказаться неудоб­ным каждый раз при вызове функции cosh задавать требуемую точность вычисле­ния суммы ряда. Конечно, можно определить точность в виде константы внутри функции, задав максимальное допустимое значение, но иногда это может оказать­ся излишним, поэтому желательно сохранить возможность задания точности че­рез параметры. Для этого либо в определении (если оно находится выше по тексту, чем любой вызов функции), либо в прототипе функции после имени параметра указывается его значение по умолчанию, например:

double cosh(double x. double eps - DBL EPSILON);

DBL EPSILON - это константа, определенная в файле <float.h>. Ее значение равно минимальному числу, которое, будучи при­бавлено к единице, даст не равный единице результат. Теперь нашу функцию можно вызывать с одним параметром, к примеру:

у - cosh(x);

Функция может иметь несколько параметров со значениями по умолчанию. Они должны находиться в конце списка параметров.

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

double cosh(const double x.int & err. const double eps = DBL EPSILON);

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

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





Дата публикования: 2015-10-09; Прочитано: 241 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.008 с)...