![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Листинг 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, кроме того, дает возможность передавать на месте этого параметра константу. Мы оформили в виде функции вычисление суммы ряда, однако задача вывода таблицы значений функции сама но себе достаточно типична и может встретиться в других задачах. Поэтому было бы логично оформить ее решение также в виде функции.
|