Программирование на языке C++ в среде Qt Creator

Использование функций при программировании на C++

Разбить на страницы
Показывать лекцию целиком

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

Подпрограмма — именованная, логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке C++ подпрограммы реализованы в виде функций [4 ]

4.1. Общие сведения о функциях. Локальные и глобальные переменные

Функция — это поименованный набор описаний и операторов, выполняющих определённую задачу. Функция может принимать параметры и возвращать значение. Информация, передаваемая в функцию для обработки, называется параметром, а результат вычисления функции её значением. Обращение к функции называют вызовом. Как известно (п. 2.8), любая программа на C++ состоит из одной или нескольких функций. При запуске программы первой выполняется функция main. Если среди операторов функции main встречается вызов функции, то управление передаётся операторам функции. Когда все операторы функции будут выполнены, управление возвращается оператору, следующему за вызовом функции.

Перед вызовом функция должна быть обязательно описана. Описание функции состоит из заголовка и тела функции:

тип имя_функции(список_переменных)
{
	тело_функции
}
		

Заголовок функции содержит:

  • тип возвращаемого функцией значения, он может быть любым; если функция не возвращает значения, указывают тип void;
  • имя_функции;
  • список_переменных — перечень передаваемых в функцию величин (аргументов), которые отделяются друг от друга запятыми; для каждой переменной из списка указывается тип и имя; если функция не имеет аргументов, то в скобках указывают либо тип void, либо ничего.
  • Тело функции представляет собой последовательность описаний и операторов, заключённых в фигурные скобки.

    В общем виде структура программы на C++ может иметь вид:

    директивы компилятора
    тип имя_1(список_переменных)
    {
    	тело_функции_1;
    }
    тип имя_2(список_переменных)
    {
    	тело_функции_2;
    }
    ...
    тип имя_n(список_переменных)
    {
    	тело_функции_n;
    }
    int main (список_переменных)
    {
    	//Тело функции может содержать операторы вызова функций имя_1, имя_2, ..., имя_n
    	тело_основной_функции;
    }
    		

    Однако допустима и другая форма записи программного кода :

    директивы компилятора
    тип имя_1(список_переменных);
    тип имя_2(список_переменных);
    ...
    тип имя_n(список_переменных);
    int main (список_переменных)
    {
    	//Тело функции может содержать операторы вызова функций имя_1, имя_2, ..., имя_n
    	тело_основной_функции;
    }
    тип имя_1(список_переменных)
    {
    	тело_функции_1;
    }
    тип имя_2(список_переменных)
    {
    	тело_функции_2;
    }
    ...
    тип имя_n(список_переменных)
    {
    	тело_функции_n;
    }
    		

    Здесь функции описаны после функции main(), однако до неё перечислены заголовки всех функций. Такого рода опережающие заголовки называют прототипами функций. Прототип указывает компилятору тип данных, возвращаемых функцией, тип переменных, выступающих в роли аргументов, и порядок их следования. Прототипы используются для проверки правильности вызова функций в основной программе. Имена переменных, указанные в прототипе функции, компилятор игнорирует:

    //Записи равносильны.
    int func ( int a, int b );
    int func ( int, int );
    		

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

    имя_функции(список_переменных);
    		

    Рассмотрим пример. Создадим функцию f(), которая не имеет входных значений и не формирует результат. При вызове этой функции на экран выводится строка символов "С Новым Годом, ".

    #include <iostream>
    using namespace std;
    void f ( ) //Описание функции.
    {
    	cout << "С Новым Годом, ";
    }
    int main ( )
    {
    	f ( ); //Вызов функции.
    	cout <<"Студент!" << endl;
    	f ( ); //Вызов функции.
    	cout <<"Преподаватель!" << endl;
    	f ( ); //Вызов функции.
    	cout <<"Народ!" << endl;
    }
    		

    Результатом работы программы будут три строки:

    С Новым Годом, Студент!
    С Новым Годом, Преподаватель!
    С Новым Годом, Народ!
    		

    Далее приведён пример программы, которая пять раз выводит на экран фразу "Здравствуй, мир!". Операция вывода строки символов оформлена в виде функции fun(). Эта функция также не имеет входных значений и не формирует результат. Вызов функции осуществляется в цикле:

    #include <iostream>
    using namespace std;
    void fun ( )
    {
    	cout << "Здравствуй, мир!" << endl;
    }
    int main ( )
    {
    	for ( int i =1; i <=5; fun ( ), i ++);
    }
    		

    Если тип возвращаемого значения не void, то функция может входить в состав выражений. Типы и порядок следования переменных в определении и при вызове функции должны совпадать. Для того чтобы функция вернула какое-либо значение, в ней должен быть оператор:

    return (выражение);
    		

    Далее приведён пример программы, которая вычисляет значение выражения $$\sin^2(\alpha)+\cos^2(\alpha)$$ при заданном значении α. Здесь функция radian выполняет перевод градусной меры угла в радианнуюЧтобы найти радианную меру какого-нибудь угла по заданной градусной мере, нужно помножить число градусов на $$\frac{\pi}{180}$$, число минут на $$\frac{\pi}{180\cdot 60}$$, число секунд на $$\frac{\pi}{180\cdot 60\cdot 60}$$ и найденные произведения сложить..

    #include <iostream>
    #include <math.h>
    #define PI 3.14159
    using namespace std;
    double radian ( int deg, int min, int sec )
    {
    	return ( deg * PI/180+min* PI /180/60+ sec * PI /180/60/60);
    }
    int main ( )
    {
    	int DEG, MIN, SEC; double RAD;
    	//Ввод данных.
    	cout<<" Input :"<<endl; //Величина угла:
    	cout<<" DEG ="; cin >>DEG; //градусы,
    	cout<<" MIN ="; cin >>MIN; //минуты,
    	cout<<" SEC ="; cin >>SEC; //секунды.
    	//Величина угла в радианах.
    	RAD=radian (DEG, MIN, SEC); //Вызов функции.
    	cout << " Value in radian A="<<RAD << endl;
    	//Вычисление значения выражения и его вывод.
    	cout << " sin (A) ^2+ cos (A) ^2= ";
    	cout << pow( sin (RAD), 2 )+pow( cos (RAD), 2 ) << endl;
    	return 0;
    }
    			

    Переменные, описанные внутри функции, а также переменные из списка аргументов, являются локальными. Например, если программа содержит пять разных функций, в каждой из которых описана переменная $$N$$, то для C++ это пять различных переменных. Область действия локальной переменной не выходит за рамки функции. Значения локальных переменных между вызовами одной и той же функции не сохраняются.

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

    4.2 Передача параметров в функцию

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

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

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

    Передача параметров в функцию может осуществляться по значению и по адресу.

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

    Если требуется запретить изменение параметра внутри функции, используют модификатор const. Заголовок функции в общем виде будет выглядеть так:

    тип имя_функции ( const тип_переменной* имя_переменной, ...)
    		

    Например:

    #include <iostream>
    using namespace std;
    int f1 ( int i ) //Данные передаются по значению
    {
    	return ( i ++);
    }
    int f2 ( int * j ) //Данные передаются по адресу. При подстановке фактического параметра,
    //для получения его значения, применяется операция разадресации * .
    {
    	return ( ( * j )++);
    }
    int f3 ( const int * k ) //Изменение параметра не предусмотрено .
    {
    	return ( ( * k )++);
    }
    int main ( )
    {
    	int a;
    	cout<<"a="; cin >>a;
    	f1( a );
    	cout<<"a="<<a<<"\n";
    	f2(a ); //Для передачи фактического параметра используется операция взятия адреса  .
    	cout<<"a="<<a<<"\n";
    	f3(a );
    	cout<<"a="<<a<<"\n";
    	return 0;
    }
    		

    Результат работы программы:

    Введено значение переменной $$a$$.

    a=5
    		

    Значение переменной a после вызова функции $$f1$$ не изменилось.

    a=5
    		

    Значение переменной a после вызова функции $$f2$$ изменилось.

    a=6
    		

    Значение переменной a после вызова функции $$f3$$ не изменилось.

    a=6
    		

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

    Далее приведён пример программы, в которой исходя из радианной меры некоторого угла вычисляется величина смежного с ним угла. На экран выводятся значения углов в градусной мере. Функция degree выполняет перевод из радианной меры в градуснуюЧтобы найти градусную меру угла по заданной радианной, нужно помножить число радиан на$$\frac{180}{\pi }$$; если из полученной дроби выделить целую часть, то получим градусы; если из числа полученного умножением оставшейся дробной части на 60, выделить целую часть, получим минуты; секунды вычисляются аналогично из дробной части минут.. Эта функция ничего не возвращает. Её аргументами являются значение переменной rad, определяющее величину угла в радианах, и адреса переменных deg, min, sec, в которых будут храниться вычисленные результаты — градусная мера угла.

    #include <iostream>
    #include <math.h>
    #define PI 3.14159
    using namespace std;
    void degree ( double rad, int * deg, int * min, int * sec )
    {
    	* deg= floor ( rad * 180/ PI );
    	* min=floor ( ( rad * 180/ PI -(* deg ) ) * 60);
    	* sec=floor ( ( ( rad * 180/ PI -(* deg ) ) *60 -(* min ) ) * 60);
    }
    int main ( )
    {
    	int DEG, MIN, SEC; double RAD;
    	cout<<" Inpout :"<<endl;
    	cout << " Value in radian A="; cin >>RAD;
    	degree (RAD,DEG,MIN,SEC);
    	cout << DEG<<" "<<MIN<<" "<<SEC << endl;
    	degree ( PI- RAD,DEG,MIN,SEC);
    	cout << DEG<<" "<<MIN<<" "<<SEC << endl;
    	return 0;
    }
    		

    4.3 Возврат результата с помощью оператора return

    Возврат результата из функции в вызывающую её функцию осуществляется оператором return выражение;

    Работает оператор следующим образом. Вычисляется значение выражения, указанного после return, и преобразуется к типу возвращаемого функцией значения. Выполнение функции завершается, а вычисленное значение передаётся в вызывающую функцию. Любые операторы, следующие в функции за оператором return, игнорируются. Программа продолжает свою работу с оператора, следующего за оператором вызова данной функции.

    Оператор return может отсутствовать в функциях типа void, если возврат происходит перед закрывающейся фигурной скобкой, и в функции main.

    Также функция может содержать несколько операторов return, если это определено потребностями алгоритма. Например, в следующей программе функция equation вычисляет корни квадратного уравнения. Если $$a = 0$$ (уравнение не является квадратным), то в программу передаётся значение равное -1, если дискриминант отрицательный (уравнение не имеет действительных корней), то 1, а если положительный, то вычисляются корни уравнения и в программу передаётся 0.

    #include <iostream>
    #include <math.h>
    using namespace std;
    int equation ( float a, float b, float c, float * x1, float * x2 )
    { float D=b*b-4*a*c;
    	if ( a==0) return -1;
    	else if (D<0) return 1;
    		else
    		{
    		*x1=(-b+sqrt (D) ) /2/ a;
    		*x2=(-b-sqrt (D) ) /2/ a;
    		return 0;
    		}
    }
    int main ( )
    {
    	float A, B, C, X1, X2; int P;
    	cout<<" Enter the coefficients of the equation :"<<endl;
    	cout<<"A="; cin >>A;
    	cout<<"B="; cin >>B;
    	cout<<"C="; cin >>C;
    	P=equation ( A, B, C, X1, X2);
    	if (P==-1) cout<<" input Error "<<endl;
    	else if (P==1) cout<<" No real roots "<<endl;
    		else cout<<" X1="<<X1<<" X2="<<X2<<endl;
    	return 0;
    }
    		

    4.4 Решение задач с использованием функций

    Рассмотрим несколько задач с применением функций.

    Задача 4.1. Вводится последовательность из $$N$$ целых чисел, найти среднее арифметическое совершённых чисел и среднее геометрическое простых чисел последовательности.

    Напомним, что целое число называется простым, если оно делится нацело только на само себя и единицу. Подробно алгоритм определения простого числа описан в задаче 3.15 (рис. 3.29). В этой задаче кроме простых чисел фигурируют совершённые числа. Число называется совершённым, если сумма всех делителей, меньших его самого, равна этому числу. Алгоритм, с помощью которого можно определить делители числа, подробно рассмотрен в задаче 3.14 (рис. 3.28).

    Для решения поставленной задачи понадобятся две функции:

  • prostoe — определяет, является ли число простым, аргумент функции целое число $$N$$; функция возвращает 1, если число простое и 0 — в противном случае.;
  • soversh — определяет, является ли число совершённым; входной параметр целое число $$N$$; функция возвращает 1, если число является совершённым и 0 — в противном случае.
  • #include <iostream>
    #include <math.h>
    unsigned int prostoe ( unsigned int N) //Описание функции.
    {
    	//Функция определяет, является ли число простым.
    	int i, pr;
    	for ( pr =1, i =2; i<=N/ 2; i ++)
    	if (N%i ==0) { pr =0; break; }
    	return pr;
    }
    unsigned int soversh ( unsigned int N) //Описание функции.
    {
    	//Функция определяет, является ли число совершённым.
    	unsigned int i, S;
    	for ( S=0, i =1; i<=N/ 2; i ++)
    		if (N%i ==0) S+=i; //Сумма делителей.
    	if ( S==N) return 1;
    	else return 0;
    }
    using namespace std;
    int main ( )
    {
    	unsigned int i,N,X, S, kp, ks;
    	long int P;
    	cout <<"N="; cin >>N;
    	for ( kp=ks=S=0,P=1, i =1; i<=N; i ++)
    	{
    		cout <<"X="; cin >> X; //Вводится элемент последовательности.
    		if ( prostoe (X) ) // X — простое число.
    		{
    			kp++; //Счётчик простых чисел.
    			P*=X; //Произведение простых чисел.
    		}
    		if ( soversh (X) ) //X — совершённое число.
    		{
    			ks++; //Счётчик совершённых чисел.
    			S+=X; //Сумма совершённых чисел.
    		}
    	}
    	if ( kp>0) //Если счётчик простых чисел больше нуля,
    		//считаем среднее геометрическое и выводим его,
    		cout<<"Среднее геометрическое="<<pow(P, ( float ) 1/kp )<<endl;
    	else //в противном случае –– сообщение об отсутствии простых чисел.
    		cout<<"Нет простых чисел\n";
    	if ( ks>0) //Если счётчик совершённых чисел больше нуля,
    		//считаем среднее арифметическое и выводим его,
    		cout<<"Среднее арифметическое="<<(float ) S/ ks<<endl;
    	else //в противном случае — сообщение об отсутствии совершённых чисел.
    		cout<<"Нет совершённых чисел\n";
    	return 0;
    }
    		

    Задача 4.2. Вводится последовательность целых чисел, 0 — конец последовательности. Найти минимальное число среди простых чисел и максимальное — среди чисел, не являющихся простыми.

    Для решения данной задачи создадим функцию prostoe, которая будет проверять, является ли число $$N$$ простым. Входным параметром функции будет целое положительное число $$N$$. Функция будет возвращать значение 1, если число простое, и 0 — в противном случае. Алгоритм поиска максимума (минимума) подробно описан в задаче 3.20 (рис. 3.31).

    Текст программы:

    #include <iostream>
    using namespace std;
    unsigned int prostoe ( unsigned int N)
    {
    	int i, pr;
    	for ( pr =1, i =2; i>=N/ 2; i ++)
    	if (N%i ==0) { pr =0; break; }
    	return pr;
    }
    int main ( )
    {
    	int kp=0,knp=0,min, max,N;
    	for ( cout << "N=", cin >>N; N != 0; cout<<"N=", cin >>N)
    		//В цикле вводится элемент последовательности N.
    		if ( prostoe (N) ) //N — простое число,
    		{
    			kp++; //счётчик простых чисел.
    			if ( kp==1) min=N; //Предполагаем, что первое простое число минимально,
    			else if (N<min ) min=N; //если найдётся меньшее число, сохраняем его.
    		}
    		else //N — простым не является,
    		{
    			knp++; //счётчик чисел не являющихся простыми.
    			if ( knp==1) max=N; //Предполагаем, что первое не простое число максимально,
    			else if (N>max) max=N; //если найдётся большее число, сохраняем его.
    		}
    		if ( kp>0) //Если счётчик простых чисел больше нуля,
    			cout <<" min = "<<min<<"\t"; //выводим значение минимального простого числа,
    		else //в противном случае —
    			cout <<"Нет простых чисел"; //сообщение об отсутствии простых чисел.
    		if ( knp>0) //Если счётчик чисел не являющихся простыми больше нуля,
    			cout <<" max ="<<max<<endl; //выводим значение максимального числа,
    		else //в противном случае —
    			cout <<"Нет составных чисел"; //сообщение об отсутствии чисел
    			//не являющихся простыми.
    	return 0;
    }
    		

    Задача 4.3. Вводится последовательность из $$N$$ целых положительных чисел. В каждом числе найти наименьшую и наибольшую цифрыВыделение цифры из числа подробно описано в задаче 3.16.

    Программный код к задаче 4.3.

    #include <iostream>
    using namespace std;
    unsigned int Cmax( unsigned long long int P)
    {
    	unsigned int max;
    	if (P==0) max=0;
    	for ( int i =1; P!=0;P/=10)
    	{
    		if ( i ==1) {max=P%10; i ++;}
    		if (P%10>max) max=P%10;
    	}
    	return max;
    }
    unsigned int Cmin( unsigned long long int P)
    {
    	unsigned int min;
    	if (P==0) min=0;
    	for ( int i =1; P!=0;P/=10)
    	{
    		if ( i ==1) {min=P%10; i ++;}
    		if (P%10<min ) min=P%10;
    	}
    	return min;
    }
    int main ( )
    {
    	unsigned int N, k;
    	unsigned long long int X;
    	for ( cout<<"N=", cin >>N, k=1;k<=N; k++)
    	{
    		cout<<"X="; cin >>X;
    		cout<<"Максимальная цифра="<<Cmax(X);
    		cout<<" Минимальная цифра="<<Cmin(X)<<endl;
    	}
    	return 0;
    }
    		

    Задача 4.4. Вводится последовательность целых положительных чисел, 0 — конец последовательности. Определить, сколько в последовательности чисел-палиндромовПалиндром — любой симметричный относительно своей середины набор символов..

    Алгоритм определения палиндрома подробно описан в задаче 3.19. Далее приведён программный код к задаче 4.4

    #include <iostream>
    using namespace std;
    bool palindrom ( unsigned long long int N)
    { //Функция определяет, является ли число N палиндромом, возвращает true, если N —
    	//палиндром, и false в противном случае
    	unsigned long int M, R, S;
    	int kol, i;
    	for (R=1, kol =1,M=N;M/10>0; kol ++,R*=10,M/=10);
    	for ( S=0,M=N, i =1; i<=kol; S+=M%10*R,M/=10,R/=10, i ++);
    		if (N==S ) return true;
    		else return false;
    }
    int main ( )
    { unsigned long long int X;
    	int K;
    	for (K=0, cout<<"X=", cin >>X;X!=0; cout<<"X=", cin >>X)
    		if ( palindrom (X) ) K++;
    			cout<<"Количество палиндромов равно K="<<K<<endl;
    	return 0;
    }
    		

    Задача 4.5. Заданы два числа — $$X$$ в двоичной системе счисления, $$Y$$ в системе счисления с основанием пять. Найти сумму этих чисел. Результат вывести в десятичной системе счисления.

    Любое целое число $$N$$, заданное в $$b$$-ичной системе счисления, можно представить в десятичной системе счисления: $$N=P_n\cdot b^b+P_{n-1}\cdot b^{n-1}+...+P_2\cdot b^2+P_1\cdot b+P_0=\sum_{i=0}^n{P_i\cdot b^i},$$ где $$b$$ — основание системы счисления (целое положительное фиксированное число), $$P_i$$ — разряд числа: $$0\leqslant P_i\leqslant b-1,i=0,1,2,...,n.$$ Например,

    $$743_{10}=7\cdot 10^2+4\cdot 10^1+3\cdot 10^0=700+40+3=743_{10};\\ 1011101_2=1\cdot 2^6+0\cdot 2^5+1\cdot 2^4+1\cdot 2^3+1\cdot 2^2+0\cdot 2^1+1\cdot 2^0=64+16+8+4+1=93_{10}.$$

    Создадим функцию для перевода целого числа $$N$$, заданного в $$b$$-ичной системе счисления, в десятичную систему счисления.

    #include <iostream>
    using namespace std;
    unsigned long long int DecNC( unsigned long long int N, unsigned int b )
    {
    	//Функция выполняет перевод числа N, заданного в b-ичной системе счисления,
    	//в десятичную систему счисления
    	unsigned long long int S, P;
    	for ( S=0,P=1;N!=0; S+=N%10*P, P*=b,N/=10);
    	return S;
    }
    int main ( )
    {
    	unsigned long long int X,Y; unsigned int bX, bY;
    	cout<<"X="; cin >>X; //Ввод числа X.
    	cout<<"b="; cin >>bX; //Ввод основания с/с.
    	cout<<"Y="; cin >>Y; //Ввод числа X.
    	cout<<"b="; cin >>bY; //Ввод основания с/с.
    	//Вывод заданных чисел в десятичной с/с.
    	cout<<X<<"("<<bX<<")="<<DecNC(X, bX)<<" (10) "<<endl;
    	cout<<Y<<"("<<bY<<")="<<DecNC(Y, bY)<<" (10) "<<endl;
    	//Вычисление суммы и вывод результата.
    	cout<<X<<"("<<bX<<")+"<<Y<<"("<<bY<<")=";
    	cout<<DecNC(X, bX)+DecNC(Y, bY)<<" (10) "<<endl;
    	return 0;
    }
    		

    Задача 4.6. Задано число $$X$$ в десятичной системе счисления. Выполнить перевод числа в системы счисления с основанием 2, 5 и 7.

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

  • Разделить данное число на основание новой системы счисления: остаток от деления — младший разряд нового числа;
  • Если частное от деления не равно нулю, продолжать деление, как указано в п.1.
  • На рис. 4.1 приведён пример "ручного" перевода числа 256, заданного в десятичной системе счисления, в восьмеричную. В результате получим $$256_{(10)}=400_{(8)}$$

    (рис 4.1) Пример перевода числа в новую систему счисления

    Далее приведён текст программы, реализующей решение задачи 4.6.

    #include <iostream>
    using namespace std;
    unsigned long long int NC( unsigned long long int N, unsigned int b )
    {
    	unsigned long long int S, P;
    	for ( S=0,P=1;N!=0; S+=N%b *P, P*=10,N/=b );
    	return S;
    }
    int main ( )
    {
    	unsigned long long int X;
    	cout<<"X="; cin >>X; //Ввод числа X.
    	//Перевод числа X в заданные системы счисления.
    	cout<<X<<" (10) ="<<NC(X, 2 )<<" (2) "<<endl;
    	cout<<X<<" (10) ="<<NC(X, 5 )<<" (5) "<<endl;
    	cout<<X<<" (10) ="<<NC(X, 7 )<<" (7) "<<endl;
    	return 0;
    }
    		

    Задача 4.7. Найти корни уравнения $$x^2-\cos (5\cdot x)=0$$.

    Для решения задачи использовать:

  • метод половинного деления,
  • метод хорд,
  • метод касательных (метод Ньютона),
  • метод простой итерации.
  • Оценить степень точности предложенных численных методов, определив, за сколько итераций был найден корень уравнения. Вычисления проводить с точностью $$\varepsilon=10^{-3}$$.

    Вообще говоря, аналитическое решение уравнения $$f(x) = 0$$ можно найти только для узкого класса функций. В большинстве случаев приходится решать уравнение (4.1) численными методами. Численное решение уравнения (4.1) проводят в два этапа: сначала необходимо отделить корни уравнения, т.е. найти достаточно тесные промежутки, в которых содержится только один корень, эти промежутки называют интервалами изоляции корня; на втором этапе проводят уточнение отделённых корней, т.е. находят корни с заданной точностью.

    Интервал можно выделить, изобразив график функции, или каким-либо другим способом. Но все способы основаны на следующем свойстве непрерывной функции: если функция $$f (x)$$ непрерывна на интервале [$$a, b$$] и на его концах имеет различные знаки, $$f (a) \cdot f (b) < 0$$, то между точками имеется хотя бы один корень. Будем считать интервал настолько малым, что в нём находится только один корень. Рассмотрим самый простой способ уточнения корней.

    Графическое решение задачи 4.7 показано на рис. 4.2. Так как функция $$f(x)=x^2-\cos (5\cdot x)$$ дважды пересекает ось абсцисс, можно сделать вывод о наличии в уравнении $$x^2-\cos (5\cdot x)=0$$ двух корней. Первый находится на интервале [-0.4; -0.2], второй принадлежит отрезку [0.2; 0.4] .

    (рис 4.2) Геометрическое решение задачи 4.7

    Рассмотрим предложенные в задаче численные методы решения нелинейных уравнений.

    Метод половинного деления (дихотомии). Пусть был выбран интервал изоляции [$$a, b$$] (рис. 4.3). Примем за первое приближение корня точку c, которая является серединой отрезка [$$a, b$$].Далее будем действовать по следующему алгоритму:

  • Находим точку $$c=\frac{a+b}{2}$$;
  • Находим значение $$f (c)$$;
  • Если $$f(a)\cdot f(c)<0$$, то корень лежит на интервале [$$a, c$$], иначе корень лежит на интервале [$$c, b$$];
  • Если величина интервала меньше либо равна $$\varepsilon$$, то найден корень с точностью $$\varepsilon$$, иначе возвращаемся к п.1.
  • Итак, для вычисления одного из корней уравнения $$ x^2-\cos (5\cdot x)=0$$ методом половинного деления достаточно знать интервал изоляции корня $$a=0.2;b=0.4$$ и точность вычисления $$\varepsilon=10^{-3}$$.

    Блок-схема алгоритма решения уравнения методом дихотомии приведена на рис. 4.4. Понятно, что здесь $$c$$ — корень заданного уравнения.

    Однако, несмотря на простоту, такое последовательное сужение интервала проводится редко, так как требует слишком большого количества вычислений.

    (рис 4.3) Графическая интерпретация метода половинного деления

    Кроме того, этот способ не всегда позволяет найти решение с заданной точностью. Рассмотрим другие способы уточнения корня. При применении этих способов будем требовать, чтобы функция $$f (x)$$ удовлетворяла следующим условиям на интервале [$$a, b$$] :

  • функция $$f (x)$$ непрерывна вместе со своими производными первого и второго порядка. Функция $$f (x)$$ на концах интервала [$$a, b$$] имеет разные знаки $$f(a)\cdot f(b)<0$$;
  • первая и вторая производные $$f'(x)$$ и $$f''(x)$$ сохраняют определённый знак на всём интервале [$$a, b$$] .
  • Метод хорд. Этот метод отличается от метода дихотомии тем, что очередное приближение берём не в середине отрезка, а в точке пересечения с осью $$X$$ (рис. 4.5) прямой, соединяющей точки ($$a, f (a)$$) и ($$b, f (b)$$).

    Запишем уравнение прямой, проходящей через точки с координатами ($$a, f (a)$$) и ($$b, f (b)$$) : $$\frac{y-f(a)}{f(b)-f(a)}=\frac{x-a}{b-a},\ \ \ y=\frac{f(b)-f(a)}{b-a}\cdot (x-a)+f(a)$$

    Прямая, заданная уравнением (4.2), пересекает ось $$X$$ при условии $$y = 0$$.

    Найдём точку пересечения хорды с осью $$X$$: $$y=\frac{f(b)-f(a)}{b-a}\cdot (x-a)+f(a),\ \ x=a-\frac{f(a)\cdot (b-a)}{f(b)-f(a)}.$$ итак, $$c=a-\frac{f(a)}{f(b)-f(a)}(b-a)$$.

    Далее необходимо вычислить значение функции в точке $$c$$. Это и будет приближённое значение корня уравнения.

    (рис 4.4) Алгоритм решения уравнения методом дихотомии

    Для вычисления одного из корней уравнения $$x^2-\cos (5\cdot x)=0$$ методом хорд достаточно знать интервал изоляции корня, например, $$a = 0.2; b = 0.4$$, и точность вычисления $$\varepsilon=10^{-3}$$. Блок-схема метода представлена на рис. 4.6.

    Метод касательных (метод Ньютона). В одной из точек интервала [$$a; b$$], пусть это будет точка $$a$$, проведём касательную (рис. 4.7). Запишем уравнение этой прямой:$$y=k\cdot x+m$$

    Так как эта прямая является касательной, и она проходит через точку $$(c,f(c))$$, то $$k=f'(c)$$.

    Следовательно, $$y=f'(x)\cdot x+m,f(c)=f'(c)\cdot c+m,m=f(c)-c\cdot f'(c),\\y=f'(c)\cdot x+f(c)-c\cdot f'(c),y=f'(c)\cdot (x-c)+f(c)$$.

    Найдём точку пересечения касательной с осью $$X$$: $$f'(c)\cdot (x-c)+f(c)=0,\ \ x=c-\frac{f(c)}{f'(c)}$$

    (рис 4.5) Графическая интерпретация метода хорд

    Если $$|f(x)|<\varepsilon$$, то точность достигнута, и точка $$x$$ — решение; иначе необходимо переменной c присвоить значение $$x$$ и провести касательную через новую точку $$c$$; так продолжать до тех пор, пока $$|f (x)|$$ не станет меньше $$\varepsilon$$. Осталось решить вопрос, что выбрать в качестве точки начального приближения $$c$$.

    В этой точке должны совпадать знаки функции и её второй производной. А так как нами было сделано допущение, что вторая и первая производные не меняют знак, то можно проверить условие $$f(x)\cdot f''(x)>0$$ на обоих концах интервала, и в качестве начального приближения взять ту точку, где это условие выполняется.

    Здесь, как и в предыдущих методах, для вычисления одного из корней уравнения $$x^2-\cos (5\cdot x)=0$$ достаточно знать интервал изоляции корня, например, $$a = 0.2; b = 0.4$$, и точность вычисления $$\varepsilon=10^{-3}$$. Блок-схема метода Ньютона представлена на рис. 4.8. Понятно, что для реализации этого алгоритма нужно найти первую и вторую производные функции $$f(x)=x^2-\cos (5\cdot x): f'(x)=2\cdot x+5\cdot \sin (5\cdot x), f(x) =2 +25 \cdot cos(5 \cdot x)$$.

    Метод простой итерации. Для решения уравнения этим методом необходимо записать уравнение (4.1) в виде $$x=\phi(x)$$, задать начальное приближение $$x_0\in [a;b]$$ и организовать следующий итерационный вычислительный процесс: $$x_{k+1}=\phi(x_k),k=0,1,2,...$$

    Вычисление прекратить, если $$|x_{k+1}-x_k|<\varepsilon$$ ($$\varepsilon$$ — точность).

    Если неравенство $$|\phi'(x)|<1$$ выполняется на всём интервале [$$a; b$$], то последовательность $$x_0, x_1, x_2,...,x_n,... , ...$$ сходится к решению $$x^*$$ (т.е. l$$\lim\limits_{k\rightarrow \infty}x_k=x^*$$).

    Значение функции $$\phi(x)$$ должно удовлетворять условию $$|\phi'(x)|<1$$ для того, чтобы можно было применить метод простых итераций. Условие $$|\phi'(x)|<1$$ является достаточным условием сходимости метода простой итерации.

    (рис 4.6) Алгоритм метода хорд

    Уравнение (4.1) можно привести к виду $$x=\phi(x)$$ следующим образом. Умножить обе части уравнения $$f (x) = 0$$ на число $$\lambda$$. К обеим частям уравнения $$\lambda\cdot f(x)=0$$ добавить число $$x$$. Получим $$x=x+\lambda\cdot f(x)$$. Это и есть уравнение вида $$x=\phi(x)$$, где

    $$\phi(x)=x+\lambda\cdot f(x)$$

    Необходимо чтобы неравенство $$|\phi"(x)|<1$$ выполнялось на интервале [$$a; b$$], следовательно, $$|\phi"(x)|=|1+\lambda\cdot f'(x)|$$ и $$|1+\lambda\cdot f'(x)|<1 (|1+\lambda\cdot f'(a)|<1, |1+\lambda\cdotf'(b)|<1)$$, а значит, с помощью подбора параметра $$\lambda$$ можно добиться выполнения условия сходимости.

    Для вычисления корней уравнения $$x^2-\cos (5\cdot x)=0$$ воспользуемся графическим решением (рис. 4.2) и определим интервал изоляции одного из корней, например, $$a = 0.2; b = 0.4$$. Подберём значение $$\lambda$$, решив неравенство $$|1+\lambda\cdot f'(x)|<1:|1+\lambda\cdot f'(a)|<1$$ и $$|1+\lambda\cdot f'(b)|<1,\\f(x)=x^{2}-\cos (5\cdot x),f'(x)=2\cdot x+5\cdot \sin (5\cdot x),\\f'(a)=2\cdot 0.2+5\cdot \sin (5\cdot 0.2)\approx 4.6, f'(b)=2\cdot 0.4+5\cdot \sin (5\cdot 0.4)\approx 5.35,\\|1+\lambda\cdot 4.6|<1$$ и $$|1+\lambda\cdot 5.35|<1$$. $$\left\{\begin{array}{l} \left\{\begin{array}{l} 1+4.6\cdot \lambda<1 \cr 1+4.6\cdot \lambda>-1 \end{array}\right.\cr \left\{\begin{array}{l} \lambda<0 \cr \lambda>-0.37 \end{array}\right. \end{array}\right. \Rightarrow \left\{\begin{array}{l} \left\{\begin{array}{l} \lambda<0 \cr \lambda>-0.4 \end{array}\right.\cr \left\{\begin{array}{l} \lambda<0 \cr \lambda>-0.37 \end{array}\right. \end{array}\right. \Rightarrow \left\{\begin{array}{l} \lambda\in (-0.4;0) \cr \lambda\in (-0.37;0) \end{array}\right.$$

    и, следовательно, $$\lambda\in (-0.37;0)$$.

    (рис 4.7) Графическая интерпретация метода касательных

    Таким образом, исходными данными для программы будут начальное значение корня уравнения $$x_0=0.2$$, значение параметра $$\lambda$$ (пусть $$\lambda= -0.2$$), и точность вычислений $$\varepsilon=0.001$$.

    Для вычисления второго корня заданного уравнения параметр $$\lambda$$ подбирают аналогично.

    Блок-схема метода простой итерации приведена на рис. 4.9.

    Далее представлен текст программы, реализующий решение задачи 4.7.

    #include <iostream>
    #include <math.h>
    using namespace std;
    //Функция, определяющая левую часть уравнения f (x) = 0.
    double f ( double x )
    {
    	return ( x *x-cos (5 * x ) );
    }
    //Функция, реализующая метод половинного деления.
    int Dichotomy ( double a, double b, double * c, double eps )
    { int k=0;
    	do
    	{
    		* c=(a+b ) / 2;
    		if ( f ( * c ) * f ( a ) <0) b=*c;
    		else a=*c;
    		k++;
    	}
    	while ( fabs ( a-b )>=eps );
    	return k;
    }
    //Функция, реализующая метод хорд.
    int Chord ( double a, double b, double * c, double eps )
    { int k=0;
    	do
    	{
    		* c=a-f ( a ) /( f ( b )-f ( a ) ) * ( b -a );
    		if ( f ( * c ) * f ( a ) >0) a=*c;
    		else b=*c;
    		k++;
    	}
    	while ( fabs ( f ( * c ) )>=eps );
    	return k;
    }
    double f1 ( double x ) //Первая производная функции f (x).
    {
    	return (2 * x+5* sin (5 * x ) );
    }
    double f2 ( double x ) //Вторая производная функции f (x).
    {
    	return (2+25* cos (5 * x ) );
    }
    //Функция, реализующая метод касательных.
    int Tangent ( double a, double b, double * c, double eps )
    { int k=0;
    	if ( f ( a ) * f2 ( a ) >0) * c=a;
    	else * c=b;
    	do
    	{
    		* c=*c-f (* c ) / f1 ( * c );
    		k++;
    	}
    	while ( fabs ( f ( * c ) )>=eps );
    	return k;
    }
    double fi ( double x, double L) //Функция, заданная выражением 4.4 .
    {
    	return ( x+L* f ( x ) );
    }
    //Функция, реализующая метод простой итерации.
    int Iteration ( double *x, double L, double eps )
    { int k=0; double x0;
    	do
    	{
    		x0=*x;
    		*x= fi(x0, L);
    		k++;
    	}
    	while ( fabs ( x0-*x )>=eps );
    	return k;
    }
    int main ( )
    {
    	double A, B, X, P;
    	double ep =0.001; //Точность вычислений.
    	int K;
    	cout<<"a="; cin >>A; //Интервал изоляции корня.
    	cout<<"b="; cin >>B;
    	cout<<"Решение уравнения x^2 - cos (5* x) =0. "<<endl;
    	cout<<"Метод дихотомии:"<<endl;
    	K=Dichotomy (A, B,X, ep );
    	cout<<"Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	cout<<"Метод хорд:"<<endl;
    	K=Chord (A, B,X, ep );
    	cout<<" Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	cout<<"Метод касательных:"<<endl;
    	K=Tangent (A, B,X, ep );
    	cout<<" Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	cout<<"Метод простой итерации:"<<endl;
    	X=A;
    	cout<<"L="; cin >>P;
    	K=Iteration (X, P, ep );
    	cout<<" Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	return 0;
    }
    				
    (рис 4.8) Алгоритм метода Ньютона (рис 4.9) Алгоритм метода простой итерации

    Результаты работы программы:

    a=0.2
    b=0.4
    Решение уравнения x^2-cos(5*x)=0.
    Метод дихотомии:
    Найденное решение x=0.296094, количество итераций k=8
    Метод хорд:
    Найденное решение x=0.296546, количество итераций k=2
    Метод касательных:
    Найденное решение x=0.296556, количество итераций k=2
    Метод простой итерации:
    L=-0.2
    Найденное решение x=0.296595, количество итераций k=3
    				

    4.5 Рекурсивные функции

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

    Рассмотрим применение рекурсии на примерах [7, 8].

    Задача 4.8. Вычислить факториал числа $$n$$.

    Вычисление факториала подробно рассмотрено в задаче 3.12 (рис. 3.25). Для решения этой задачи с применением рекурсии создадим функцию factoial, алгоритм которой представлен на рис. 4.10.

    (рис 4.10) Рекурсивный алгоритм вычисления факториала

    Текст программы с применением рекурсии:

    #include <iostream>
    using namespace std;
    long int factorial ( int n )
    {
    	if ( n<=1)
    	return n;
    	else
    	return n*factorial ( n-1);
    }
    int main ( )
    {
    	int i; long int f;
    	cout<<"i="; cin >>i;
    	f=factorial ( i );
    	cout<<i <<" !="<<f<<"\n";
    	return 0;
    }
    				

    Задача 4.9. Вычислить $$n$$-ю степень числа $$a$$ ($$n$$ — целое число).

    Результатом возведения числа $$a$$ в целую степень $$n$$ является умножение этого числа на себя $$n$$ раз. Но это утверждение верно только для положительных значений $$n$$. Если $$n$$ принимает отрицательные значения, то $$a^{-n}=\frac{1}{a^n}$$.В случае $$n=0,\ \ a^0=1$$.

    Для решения задачи создадим рекурсивную функцию stepen, алгоритм которой представлен на рис. 4.11.

    (рис 4.11) Рекурсивный алгоритм вычисления степени числа

    Текст программы с применением рекурсии:

    #include <iostream>
    using namespace std;
    float stepen ( float a, int n )
    {
    	if ( n==0)
    		return 1;
    	else if ( n<0)
    		return 1/ stepen ( a,-n );
    	else
    	return a * stepen ( a, n-1);
    }
    int main ( )
    {
    	int i; float s, b;
    	cout<<"b="; cin >>b;
    	cout<<"i="; cin >>i;
    	s=stepen ( b, i );
    	cout<<"s="<<s<<"\n";
    	return 0;
    }
    				

    Задача 4.10. Вычислить $$n$$-е число Фибоначчи.

    Если нулевой элемент последовательности равен нулю, первый — единице, а каждый последующий представляет собой сумму двух предыдущих, то это последовательность чисел Фибоначчи (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ... ).

    Алгоритм рекурсивной функции fibonachi изображён на рис. 4.12.

    (рис 4.12) Рекурсивный алгоритм вычисления числа Фибоначчи

    Текст программы:

    #include <iostream>
    using namespace std;
    long int fibonachi ( unsigned int n )
    {
    	if ( ( n==0) | | ( n==1))
    	return n;
    	else
    	return fibonachi ( n -1)+fibonachi ( n-2);
    }
    int main ( )
    {
    	int i; long int f;
    	cout<<"i="; cin >>i;
    	f=fibonachi ( i );
    	cout<<"f="<<f<<"\n";
    	return 0;
    }
    				

    4.6 Перегрузка функций

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

    В приведённом далее тексте программы три функции с именем Pow. Первая выполняет операцию возведения вещественного числа $$a$$ в дробную степень $$n=\frac{k}{m}$$, где $$k$$ и $$m$$ — целые числа. Вторая возводит вещественное число $$a$$ в целую степень $$n$$, а третья — целое число $$a$$ в целую степень Как известно, операция $$a^n$$ не определена при $$a = 0$$ и $$n = 0$$, а так же при возведении отрицательного значения $$a$$ в дробную степень $$n=\frac{k}{m}$$, где $$m$$ — чётное число (п. 2.7).Пусть наши функции в этих случаях возвращают 0. $$n$$. Какую именно функцию вызвать компилятор определяет по типу фактических параметров. Так, если $$a$$ — вещественное число, а $$k$$ — целое, то оператор Pow(a,k) вызовет вторую функцию, так как она имеет заголовок float Pow(float a, int n). Команда Pow((int)a,k) приведёт к вызову третьей функции float Pow(int a, int n), так как вещественная переменная $$a$$ преобразована к целому типу. Первая функция float Pow(float a, int k, int m) имеет три параметра, значит, обращение к ней осуществляется командой Pow(a,k,m).

    #include <iostream>
    using namespace std;
    #include <math.h>
    float Pow( float a, int k, int m) //Первая функция
    {
    	cout<<"Функция 1 \t";
    	if ( a==0)
    	return 0;
    	else if ( k==0)
    	return 1;
    	else if ( a>0)
    	return exp ( ( float ) k/m *log ( a ) );
    	else if (m%2!=0)
    	return -(exp ( ( float ) k/m *log (-a ) ) );
    }
    float Pow( float a, int n ) //Вторая функция
    {
    	float p; int i;
    	cout<<"Функция 2 \t";
    	if ( a==0)
    		return 0;
    	else if ( n==0)
    		return 1;
    	else if ( n<0)
    	{
    		n= -n;
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return ( float ) 1/p;
    	}
    	else
    	{
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return p;
    	}
    }
    float Pow( int a, int n ) //Третья функция
    {
    	int i, p;
    	cout<<"Функция 3 \t";
    	if ( a==0)
    		return 0;
    	else if ( n==0)
    		return 1;
    	else if ( n<0)
    	{
    		n= -n;
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return ( float ) 1/p;
    	}
    	else
    	{
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return p;
    	}
    }
    int main ( )
    {
    	float a; int k, n,m;
    	cout<<"a="; cin >>a;
    	cout<<"k="; cin >>k;
    	cout<<"s="<<Pow( a, k )<<"\n"; //Вызов 2-й функции.
    	cout<<"s="<<Pow ( ( int ) a, k )<<"\n"; //Вызов 3-й функции.
    	cout<<"a="; cin >>a;
    	cout<<"k="; cin >>k;
    	cout<<"m="; cin >>m;
    	cout<<"s="<<Pow( a, k,m)<<endl; //Вызов 1-й функции.
    	return 0;
    }
    				

    Результаты работы программы:

    a=5.2
    k=3
    Функция 2 s=140.608
    Функция 3 s=125
    a=-8
    k=1
    m=1
    Функция 1 s=-8
    a=5.2
    k=-3
    Функция 2 s=0.00711197
    Функция 3 s=0.008
    a=-8
    k=1
    m=3
    Функция 1 s=-2
    				

    4.7 Шаблоны функций

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

    Простейшую функцию–шаблон в общем виде можно записать так [6]:

    template <class Type> заголовок
    {
    	тело функции
    }
    				

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

    Рассмотрим пример шаблона поиска наименьшего из четырёх чисел.

    #include <iostream>
    using namespace std;
    //Определяем абстрактный тип данных с помощью служебного слова Type .
    template <class Type>
    Type minimum( Type a, Type b, Type c, Type d )
    { //Определяем функцию с использованием типа данных Type .
    	Type min=a;
    	if ( b<min ) min=b;
    	if ( c<min ) min=c;
    	if ( d<min ) min=d;
    	return min;
    }
    int main ( )
    {
    	int ia, ib, ic, id, mini; float ra, rb, rc, rd, minr;
    	cout<<" Vvod 4 thelih chisla \t";
    	cin >>ia >>ib>>ic >>id;
    	mini=minimum( ia, ib, ic, id ); //Вызов функции minimum, в которую передаём
    	//4 целых значения.
    	cout<<"\n"<<mini<<"\n";
    	cout<<" Vvod 4 vecshestvenih chisla \t"; cin >>ra>>rb>>rc>>rd;
    	minr=minimum( ra, rb, rc, rd ); //Вызов функции minimum, в которую передаём
    	//4 вещественных значения.
    	cout<<"\n"<<minr<<"\n";
    	return 0;
    }
    				

    4.8 Область видимости переменных в функциях

    Как известно (п. 2.8), по месту объявления переменные в языке C++ делятся на три класса: локальные, глобальные и переменные, описанные в списке формальных параметров функций. Все эти переменные имеют разную область видимости.

    Локальные переменные объявляются внутри функции и доступны только в ней. О таких переменных говорят, что они имеют локальную видимость, то есть, видимы только внутри функции.

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

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

    Из функции, где действует локальное описание переменной, можно обратиться к глобальной переменной с таким же именем, используя оператор расширения области видимости

    ::переменная;
    				

    Рассмотрим пример:

    #include <iostream>
    using namespace std;
    float pr =100.678; //Переменная pr определена глобально.
    int prostoe ( int n )
    {
    	int pr =1, i; //Переменная pr определена локально.
    	if ( n<0) pr =0;
    	else
    	for ( i =2; i<=n / 2; i ++)
    		if ( n%i ==0){ pr =0; break; }
    			cout<<" local pr="<<pr<<"\n"; //Вывод локальной переменной.
    	cout<<" global pr=" <<::pr<<"\n"; //Вывод глобальной переменной.
    	return pr;
    }
    int main ( )
    {
    	int g;
    	cout<<"g="; cin >>g;
    	if ( prostoe ( g ) ) cout<<"g - prostoe \n";
    	else cout<<"g - ne prostoe \n";
    	return 0;
    }
    				

    Результаты работы программы:

    	g=7
    	local pr=1 //Локальная переменная.
    	global pr=100.678 //Глобальная переменная.
    	g - prostoe
    				

    4.9 Функция main(). Параметры командной строки

    Итак, любая программа на C++ состоит из одной или нескольких функций, причём одна из них должна обязательно носить имя main (основной, главный ). Именно этой функции передаётся управление после запуска программы. Как любая функция, main может принимать параметры и возвращать значения. У функции main две формы записи:

  • без параметров:
    тип main ( ) {тело функции },
    				
  • и с двумя параметрами:
    тип main ( int argc, char *argv [ ] ) {тело функции }
    				
    .
  • Первый параметр argc определяет количество параметров, передаваемых в функцию main из командной строки. Второй параметр argv — указатель на массив указателей типа char (массив строк). Каждый элемент массива ссылается на отдельный параметр командной строки. При стандартном запуске программы argc равно 1, argv — массив из одного элемента, этим элементом является имя запускаемого файла.

    Рассмотрим следующую программу.

    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    int main ( int argc, char * argv [ ] )
    {
    	int i;
    	cout<<"В командной строке "<<argc<<" аргументов\n";
    	for ( i =0; i <argc; i ++)
    	cout<<"Аргумент № "<<i <<" "<<argv [ i ]<<endl;
    	return 0;
    }
    				

    Текст программы хранится в файле 1.cpp. При стандартном запуске программа выведет следующую информацию:

    В командной строке 1 аргументов
    Аргумент № 0 ./1
    				

    Программа выводит количество параметров командной строки и последовательно все параметры. При стандартном запуске – количество аргументов командной строки — 1, этим параметром является имя запускаемого файла (в нашем случае, имя запускаемого файла — ./1).

    Запустим программу следующим образом:

    ./1 abc 34 6 + 90 Вася Маша
    				

    Результаты работы программы представлены ниже.

    В командной строке 8 аргументов
    Аргумент № 0 ./1
    Аргумент № 1 abc
    Аргумент № 2 34
    Аргумент № 3 6
    Аргумент № 4 +
    Аргумент № 5 90
    Аргумент № 6 Вася
    Аргумент № 7 Маша
    				

    Рассмотрим приложение, в которое в качестве параметров командной строки передаётся число1, операция, число2. Функция выводит

    число1 операция число2.
    				

    Текст программы приведён на нижеФункция atof преобразовывает строку символов в вещественное число, а если преобразование невозможно, то результатом функции atof будет число 0.0. Функция strcmp сравнивает две строки и возвращает 0 в случае совпадения строк. Подробнее об этих функциях можно прочесть в главе, посвящённой строкам.

    #include <iostream>
    #include <stdlib.h>
    #include <cstring>
    using namespace std;
    int main ( int argc, char **argv )
    {
    	//Если количество параметров больше или равно 4, то были введены два числа и знак операции.
    	if ( argc >=4)
    	//Если операция *, то выводим число1*число2.
    	{
    		if ( ! strcmp ( argv [ 2 ], "*" ) ) cout<<atof ( argv [ 1 ] ) * atof ( argv [ 3 ] )<<endl;
    		else
    		//Если операция +, то выводим число1+число2.
    		if ( ! strcmp ( argv [ 2 ], "+" ) ) cout<<atof ( argv [ 1 ] )+atof ( argv [ 3 ] )<<endl;
    		else
    		//Если операция -, то выводим число1-число2.
    		if ( ! strcmp ( argv [ 2 ], " -" ) ) cout<<atof ( argv [ 1 ] ) -atof ( argv [ 3 ] )<<endl;
    		else
    		//Если операция /, то выводим число1/число2.
    		if ( ! strcmp ( argv [ 2 ], "/" ) ) cout<<atof ( argv [ 1 ] ) / atof ( argv [ 3 ] )<<endl;
    		else cout<<"неправильный знак операции"<<endl;
    	}
    	else
    	cout<<"недостаточное количество операндов"<<endl;
    	return 0;
    }
    				

    Ниже приведены варианты запуска программы и результаты её работыТекст программы хранится в файле 4.cpp. Имя исполняемого файла ./4 (ОС Lnux). Предлагаем читателю самостоятельно разобраться с результатами всех тестовых запусков приложения.

    ./4 1.3 + 7.8
    9.1
    ./4 1.3 - 7.8
    -6.5
    ./4 1.3 / 7.8
    0.166667
    ./4 1.3 \* 7.8
    10.14
    ./4 1.3 % 7.8
    неправильный знак операции
    ./4 1.3+ 7.8
    недостаточное количество операндов
    				

    4.10 Задачи для самостоятельного решения

    4.10.1 Применение функций при работе с последовательностями чисел

    Разработать программу на языке C++ для следующих заданий:

  • Вводится последовательность целых положительных чисел, 0 — конец последовательности. Для каждого элемента последовательности определить и вывести на экран число, которое получится после записи цифр исходного числа в обратном порядке.
  • Вводится последовательность целых чисел, 0 — конец последовательности. Определить, содержит ли последовательность хотя бы одно совершённое число. Совершённое число равно сумме всех своих делителей, не превосходящих это число. Например, 6 = 1 + 2 + 3 или 28 = 1 + 2 + 4 + 7 + 14.
  • Вводится последовательность из N целых положительных элементов. Определить, содержит ли последовательность хотя бы одно простое число. Простое число не имеет делителей, кроме единицы и самого себя.
  • Вводится последовательность из $$N$$ целых положительных элементов. Посчитать количество чисел-палиндромов. Числа-палиндромы симметричны относительно своей середины, например, 12021 или 454.
  • Вводится последовательность из $$N$$ целых положительных элементов. Подсчитать количество совершённых и простых чисел в последовательности.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Определить, в каком из чисел больше всего делителей.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Определить, в каком из чисел больше всего цифр.
  • Вводится последовательность из $$N$$ целых положительных элементов. Проверить, содержит ли последовательность хотя бы одну пару соседних дружественных чисел. Два различных натуральных числа являются дружественными, если сумма всех делителей первого числа (кроме самого числа) равна второму числу. Например, 220 и 284, 1184 и 1210, 2620 и 2924, 5020 и 5564.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Каждый элемент последовательности представляет собой номер m одного из чисел Фибоначчи. Вычислить и вывести на экран m-е число Фибоначчи. Напомним, что в последовательности Фибоначчи каждое последующее число представляет собой сумму двух предыдущих (0, 1, 1, 2, 3, 5, 8, 13, 21, 34,...). Например, четвёртое число Фибоначчи равно 3, седьмое — 13, а девятое — 34.
  • Вводится последовательность из $$N$$ целых положительных элементов. Найти число с минимальным количеством цифр.
  • Вводится последовательность из$$ N$$ целых элементов. Для всех положительных элементов последовательности вычислить значение факториала. Вывести на экран число и его факториал.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Вывести на экран все числа последовательности, являющиеся составными и их делители. Составное число имеет более двух делителей, то есть не является простым.
  • Вводится последовательность из $$N$$ целых положительных элементов. Определить, содержит ли последовательность хотя бы одно число Армстронга. Число Армстронга — натуральное число, которое равно сумме своих цифр, возведённых в степень, равную количеству его цифр. Например, десятичное число 153 — число Армстронга, потому что: 13+ 33+ 53=1 + 27 + 125 = 153.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Найти среднее арифметическое простых чисел в этой последовательности. Простое число не имеет делителей, кроме единицы и самого себя.
  • Вводится последовательность из $$N$$ целых положительных элементов. Определить, сколько в последовательности пар соседних взаимно простых чисел. Различные натуральные числа являются взаимно простыми, если их наибольший общий делитель равен единице.
  • В последовательности из $$N$$ целых положительных элементов найти сумму всех недостаточных чисел. Недостаточное число всегда больше суммы всех своих делителей за исключением самого числа.
  • Вводится последовательность из $$N$$ целых положительных элементов. Посчитать количество элементов последовательности, имеющих в своём представлении цифру 0.
  • Вводится $$N$$ пар целых положительных чисел $$a$$ и $$b$$. В случае, если $$a > b$$ вычислить: $$C=\frac{a!}{b!\cdot (a-b)!}$$.
  • Вводится последовательность из $$N$$ целых элементов. Для каждого элемента последовательности найти среднее значение его цифр.
  • Вводится последовательность целых положительных чисел, 0 — конец последовательности. Для каждого элемента последовательности определить и вывести на экран число, которое получится, если поменять местами первую и последнюю цифры исходного числа.
  • Вводится последовательность из $$N$$ целых элементов. Для каждого элемента последовательности вывести на экран количество цифр и количество делителей.
  • Вводится последовательность из $$N$$ целых положительных элементов. Среди элементов последовательности найти наибольшее число-палиндром. Числа-палиндромы симметричны относительно своей середины, например, 12021 или 454.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Для каждого элемента последовательности вывести на экран сумму квадратов его цифр.
  • Вводится последовательность из $$N$$ целых положительных элементов. Для простых элементов последовательности определить сумму цифр. Простое число не имеет делителей, кроме единицы и самого себя.
  • Вводится последовательность целых положительных чисел, 0 — конец последовательности. Среди элементов последовательности найти наименьшее составное число. Составное число имеет более двух делителей, то есть не является простым.
  • 4.10.2 Применение функций для вычислений в различных системах счисления

    Разработать программу на языке C++ для решения следующей задачи. Заданы два числа — $$A$$ и $$B$$, первое в системе счисления с основанием $$p$$, второе в системе счисления с основанием $$q$$. Вычислить значение $$C$$ по указанной формуле и вывести его на экран в десятичной системе счисления и системе счисления с основанием $$r$$. Исходные данные для решения задачи представлены в табл. 4.1.

    Задания для решения задачи о различных системах счисления
    Вариант p q C r
    1 2 8 $$A^{2}\cdot (A+B)$$ 3
    2 3 4 $$2\cdot (A^{2}+B^{2})$$ 4
    3 4 6 $$2\cdot B^{2}\cdot (A+B)$$ 5
    4 5 2 $$(A-B)^{2}+3\cdot A$$ 6
    5 6 4 $$A^{2}+A\cdot B$$ 7
    6 7 3 $$(5\cdot B-2\cdot A)^{2}$$ 8
    7 8 2 $$(2\cdot A-3\cdot B)^{2}$$ 5
    8 3 8 $$(B-A)^{2}+2\cdot A$$ 6
    9 4 7 $$B^{3}-B^{2}+2\cdot A$$ 2
    10 5 6 $$A^{3}-A^{2}+3\cdot B$$ 8
    11 6 5 $$(2\cdot A-3\cdot B)^{2}$$ 3
    12 7 4 $$A^{2}+2\cdot A+B^{2}$$ 5
    13 8 3 $$A^{2}+3\cdot B+B^{2}$$ 7
    14 4 2 $$A^{2}-2\cdot A+B$$ 6
    15 5 8 $$3\cdot B^{2}-2\cdot B+A$$ 3
    16 6 7 $$A^{2}+(B-A)^{2}$$ 2
    17 7 6 $$3\cdot B^{2}+2\cdot A\cdot B$$ 8
    18 8 5 $$2\cdot A^{2}+3\cdot A\cdot B$$ 7
    19 2 4 $$B^{3}-2\cdot B+A$$ 3
    20 3 8 $$A^{3}-2\cdot A+B$$ 4
    21 4 7 $$(5\cdot A-2\cdot B)^{2}$$ 5
    22 5 6 $$(B^{2}-3\cdot A)^{2}$$ 7
    23 6 5 $$(A^{2}-2\cdot B)^{2}$$ 8
    24 7 4 $$A^{2}\cdot B^{2}-A\cdot B$$ 6
    25 8 3 $$A\cdot B+A^{2}-B$$ 2

    4.10.3 Применение функций для решения нелинейных уравнений

    Разработать программу на языке C++ для вычисления одного из корней уравнения $$f (x) = 0$$ методами, указанными в задании. Для решения задачи предварительно определить интервал изоляции корня графическим методом. Вычисления проводить с точностью $$\varepsilon=10^{-4}$$. Оценить степень точности путём подсчёта количества итераций, выполненных для достижения заданной точности. Исходные данные для решения задачи представлены в табл. 4.2.

    Задания к задаче о решении нелинейных уравнений
    Уравнение f (x) = 0 Методы решения
    1 $$x-0.2\cdot \sin (x+0.5)=0$$ метод половинного деления, метод хорд
    2 $$x^2-\lg(x+2)=0$$ метод касательных, метод простой итерации
    3 $$x^2-20\cdot \sin (x)=0$$ метод хорд, метод касательных
    4 $$\ln (x)+(x+1)^3=0$$ метод дихотомии, метод простой итерации
    5 $$x^2-\sin(5x)=0$$ метод половинного деления, метод касательных
    6 $$e^x+x^2-2=0$$ метод хорд, метод простой итерации
    7 $$0.8\cdot x^{2}-\sin (10\cdot x)=0$$ метод половинного деления, метод хорд
    8 $$\sin (7\cdot x)+2\cdot x-6=0$$ метод касательных, метод простой итерации
    9 $$x\cdot \ln (x)-1=0$$ метод хорд, метод касательных
    10 $$2\cdot \lg(x)+0.5\cdot x=0$$ метод дихотомии, метод простой итерации
    11 $$e^{-x}-x^2=0$$ метод половинного деления, метод касательных
    12 $$x^2-3\cdot \cos (x^2)=0$$ метод хорд, метод простой итерации
    13 $$\sin (7\cdot x)-x^2+15=0$$ метод половинного деления, метод хорд
    14 $$(x-1)^2-0.5\cdot e^x=0$$ метод касательных, метод простой итерации
    15 $$2\cdot \ln (x)-0.2\cdot x+1=0$$ метод хорд, метод касательных
    16 $$2-x\cdot e^x=0$$ метод дихотомии, метод простой итерации
    17 $$0.1\cdot x^3+3\cdot x^2-10\cdot x-7=0$$ метод половинного деления, метод касательных
    18 $$0.1\cdot x^2-e^x=0$$ метод хорд, метод простой итерации
    19 $$e^{-2\cdot x}-2\cdot x+1=0$$ метод половинного деления, метод хорд
    20 $$x^2-3+0.5^x=0$$ метод касательных, метод простой итерации
    21 $$\lg(4\cdot x)-\cos (x)=0$$ метод хорд, метод касательных
    22 $$\ln(x)-\cos^2(x)=0$$ метод дихотомии, метод простой итерации
    23 $$\frac{4}{x}-0.2\cdot e^x=0$$ метод половинного деления, метод касательных
    24 $$\sqrt{x+6.5}-e^x=0$$ метод хорд, метод простой итерации
    25 $$0.5^x+1-(x-2)^2=0$$ метод половинного деления, метод хорд
    Страницы:

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

    Подпрограмма — именованная, логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке C++ подпрограммы реализованы в виде функций [4 ]

    4.1. Общие сведения о функциях. Локальные и глобальные переменные

    Функция — это поименованный набор описаний и операторов, выполняющих определённую задачу. Функция может принимать параметры и возвращать значение. Информация, передаваемая в функцию для обработки, называется параметром, а результат вычисления функции её значением. Обращение к функции называют вызовом. Как известно (п. 2.8), любая программа на C++ состоит из одной или нескольких функций. При запуске программы первой выполняется функция main. Если среди операторов функции main встречается вызов функции, то управление передаётся операторам функции. Когда все операторы функции будут выполнены, управление возвращается оператору, следующему за вызовом функции.

    Перед вызовом функция должна быть обязательно описана. Описание функции состоит из заголовка и тела функции:

    тип имя_функции(список_переменных)
    {
    	тело_функции
    }
    		

    Заголовок функции содержит:

  • тип возвращаемого функцией значения, он может быть любым; если функция не возвращает значения, указывают тип void;
  • имя_функции;
  • список_переменных — перечень передаваемых в функцию величин (аргументов), которые отделяются друг от друга запятыми; для каждой переменной из списка указывается тип и имя; если функция не имеет аргументов, то в скобках указывают либо тип void, либо ничего.
  • Тело функции представляет собой последовательность описаний и операторов, заключённых в фигурные скобки.

    В общем виде структура программы на C++ может иметь вид:

    директивы компилятора
    тип имя_1(список_переменных)
    {
    	тело_функции_1;
    }
    тип имя_2(список_переменных)
    {
    	тело_функции_2;
    }
    ...
    тип имя_n(список_переменных)
    {
    	тело_функции_n;
    }
    int main (список_переменных)
    {
    	//Тело функции может содержать операторы вызова функций имя_1, имя_2, ..., имя_n
    	тело_основной_функции;
    }
    		

    Однако допустима и другая форма записи программного кода :

    директивы компилятора
    тип имя_1(список_переменных);
    тип имя_2(список_переменных);
    ...
    тип имя_n(список_переменных);
    int main (список_переменных)
    {
    	//Тело функции может содержать операторы вызова функций имя_1, имя_2, ..., имя_n
    	тело_основной_функции;
    }
    тип имя_1(список_переменных)
    {
    	тело_функции_1;
    }
    тип имя_2(список_переменных)
    {
    	тело_функции_2;
    }
    ...
    тип имя_n(список_переменных)
    {
    	тело_функции_n;
    }
    		

    Здесь функции описаны после функции main(), однако до неё перечислены заголовки всех функций. Такого рода опережающие заголовки называют прототипами функций. Прототип указывает компилятору тип данных, возвращаемых функцией, тип переменных, выступающих в роли аргументов, и порядок их следования. Прототипы используются для проверки правильности вызова функций в основной программе. Имена переменных, указанные в прототипе функции, компилятор игнорирует:

    //Записи равносильны.
    int func ( int a, int b );
    int func ( int, int );
    		

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

    имя_функции(список_переменных);
    		

    Рассмотрим пример. Создадим функцию f(), которая не имеет входных значений и не формирует результат. При вызове этой функции на экран выводится строка символов "С Новым Годом, ".

    #include <iostream>
    using namespace std;
    void f ( ) //Описание функции.
    {
    	cout << "С Новым Годом, ";
    }
    int main ( )
    {
    	f ( ); //Вызов функции.
    	cout <<"Студент!" << endl;
    	f ( ); //Вызов функции.
    	cout <<"Преподаватель!" << endl;
    	f ( ); //Вызов функции.
    	cout <<"Народ!" << endl;
    }
    		

    Результатом работы программы будут три строки:

    С Новым Годом, Студент!
    С Новым Годом, Преподаватель!
    С Новым Годом, Народ!
    		

    Далее приведён пример программы, которая пять раз выводит на экран фразу "Здравствуй, мир!". Операция вывода строки символов оформлена в виде функции fun(). Эта функция также не имеет входных значений и не формирует результат. Вызов функции осуществляется в цикле:

    #include <iostream>
    using namespace std;
    void fun ( )
    {
    	cout << "Здравствуй, мир!" << endl;
    }
    int main ( )
    {
    	for ( int i =1; i <=5; fun ( ), i ++);
    }
    		

    Если тип возвращаемого значения не void, то функция может входить в состав выражений. Типы и порядок следования переменных в определении и при вызове функции должны совпадать. Для того чтобы функция вернула какое-либо значение, в ней должен быть оператор:

    return (выражение);
    		

    Далее приведён пример программы, которая вычисляет значение выражения $$\sin^2(\alpha)+\cos^2(\alpha)$$ при заданном значении α. Здесь функция radian выполняет перевод градусной меры угла в радианнуюЧтобы найти радианную меру какого-нибудь угла по заданной градусной мере, нужно помножить число градусов на $$\frac{\pi}{180}$$, число минут на $$\frac{\pi}{180\cdot 60}$$, число секунд на $$\frac{\pi}{180\cdot 60\cdot 60}$$ и найденные произведения сложить..

    #include <iostream>
    #include <math.h>
    #define PI 3.14159
    using namespace std;
    double radian ( int deg, int min, int sec )
    {
    	return ( deg * PI/180+min* PI /180/60+ sec * PI /180/60/60);
    }
    int main ( )
    {
    	int DEG, MIN, SEC; double RAD;
    	//Ввод данных.
    	cout<<" Input :"<<endl; //Величина угла:
    	cout<<" DEG ="; cin >>DEG; //градусы,
    	cout<<" MIN ="; cin >>MIN; //минуты,
    	cout<<" SEC ="; cin >>SEC; //секунды.
    	//Величина угла в радианах.
    	RAD=radian (DEG, MIN, SEC); //Вызов функции.
    	cout << " Value in radian A="<<RAD << endl;
    	//Вычисление значения выражения и его вывод.
    	cout << " sin (A) ^2+ cos (A) ^2= ";
    	cout << pow( sin (RAD), 2 )+pow( cos (RAD), 2 ) << endl;
    	return 0;
    }
    			

    Переменные, описанные внутри функции, а также переменные из списка аргументов, являются локальными. Например, если программа содержит пять разных функций, в каждой из которых описана переменная $$N$$, то для C++ это пять различных переменных. Область действия локальной переменной не выходит за рамки функции. Значения локальных переменных между вызовами одной и той же функции не сохраняются.

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

    4.2 Передача параметров в функцию

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

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

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

    Передача параметров в функцию может осуществляться по значению и по адресу.

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

    Если требуется запретить изменение параметра внутри функции, используют модификатор const. Заголовок функции в общем виде будет выглядеть так:

    тип имя_функции ( const тип_переменной* имя_переменной, ...)
    		

    Например:

    #include <iostream>
    using namespace std;
    int f1 ( int i ) //Данные передаются по значению
    {
    	return ( i ++);
    }
    int f2 ( int * j ) //Данные передаются по адресу. При подстановке фактического параметра,
    //для получения его значения, применяется операция разадресации * .
    {
    	return ( ( * j )++);
    }
    int f3 ( const int * k ) //Изменение параметра не предусмотрено .
    {
    	return ( ( * k )++);
    }
    int main ( )
    {
    	int a;
    	cout<<"a="; cin >>a;
    	f1( a );
    	cout<<"a="<<a<<"\n";
    	f2(a ); //Для передачи фактического параметра используется операция взятия адреса  .
    	cout<<"a="<<a<<"\n";
    	f3(a );
    	cout<<"a="<<a<<"\n";
    	return 0;
    }
    		

    Результат работы программы:

    Введено значение переменной $$a$$.

    a=5
    		

    Значение переменной a после вызова функции $$f1$$ не изменилось.

    a=5
    		

    Значение переменной a после вызова функции $$f2$$ изменилось.

    a=6
    		

    Значение переменной a после вызова функции $$f3$$ не изменилось.

    a=6
    		

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

    Далее приведён пример программы, в которой исходя из радианной меры некоторого угла вычисляется величина смежного с ним угла. На экран выводятся значения углов в градусной мере. Функция degree выполняет перевод из радианной меры в градуснуюЧтобы найти градусную меру угла по заданной радианной, нужно помножить число радиан на$$\frac{180}{\pi }$$; если из полученной дроби выделить целую часть, то получим градусы; если из числа полученного умножением оставшейся дробной части на 60, выделить целую часть, получим минуты; секунды вычисляются аналогично из дробной части минут.. Эта функция ничего не возвращает. Её аргументами являются значение переменной rad, определяющее величину угла в радианах, и адреса переменных deg, min, sec, в которых будут храниться вычисленные результаты — градусная мера угла.

    #include <iostream>
    #include <math.h>
    #define PI 3.14159
    using namespace std;
    void degree ( double rad, int * deg, int * min, int * sec )
    {
    	* deg= floor ( rad * 180/ PI );
    	* min=floor ( ( rad * 180/ PI -(* deg ) ) * 60);
    	* sec=floor ( ( ( rad * 180/ PI -(* deg ) ) *60 -(* min ) ) * 60);
    }
    int main ( )
    {
    	int DEG, MIN, SEC; double RAD;
    	cout<<" Inpout :"<<endl;
    	cout << " Value in radian A="; cin >>RAD;
    	degree (RAD,DEG,MIN,SEC);
    	cout << DEG<<" "<<MIN<<" "<<SEC << endl;
    	degree ( PI- RAD,DEG,MIN,SEC);
    	cout << DEG<<" "<<MIN<<" "<<SEC << endl;
    	return 0;
    }
    		

    4.3 Возврат результата с помощью оператора return

    Возврат результата из функции в вызывающую её функцию осуществляется оператором return выражение;

    Работает оператор следующим образом. Вычисляется значение выражения, указанного после return, и преобразуется к типу возвращаемого функцией значения. Выполнение функции завершается, а вычисленное значение передаётся в вызывающую функцию. Любые операторы, следующие в функции за оператором return, игнорируются. Программа продолжает свою работу с оператора, следующего за оператором вызова данной функции.

    Оператор return может отсутствовать в функциях типа void, если возврат происходит перед закрывающейся фигурной скобкой, и в функции main.

    Также функция может содержать несколько операторов return, если это определено потребностями алгоритма. Например, в следующей программе функция equation вычисляет корни квадратного уравнения. Если $$a = 0$$ (уравнение не является квадратным), то в программу передаётся значение равное -1, если дискриминант отрицательный (уравнение не имеет действительных корней), то 1, а если положительный, то вычисляются корни уравнения и в программу передаётся 0.

    #include <iostream>
    #include <math.h>
    using namespace std;
    int equation ( float a, float b, float c, float * x1, float * x2 )
    { float D=b*b-4*a*c;
    	if ( a==0) return -1;
    	else if (D<0) return 1;
    		else
    		{
    		*x1=(-b+sqrt (D) ) /2/ a;
    		*x2=(-b-sqrt (D) ) /2/ a;
    		return 0;
    		}
    }
    int main ( )
    {
    	float A, B, C, X1, X2; int P;
    	cout<<" Enter the coefficients of the equation :"<<endl;
    	cout<<"A="; cin >>A;
    	cout<<"B="; cin >>B;
    	cout<<"C="; cin >>C;
    	P=equation ( A, B, C, X1, X2);
    	if (P==-1) cout<<" input Error "<<endl;
    	else if (P==1) cout<<" No real roots "<<endl;
    		else cout<<" X1="<<X1<<" X2="<<X2<<endl;
    	return 0;
    }
    		

    4.4 Решение задач с использованием функций

    Рассмотрим несколько задач с применением функций.

    Задача 4.1. Вводится последовательность из $$N$$ целых чисел, найти среднее арифметическое совершённых чисел и среднее геометрическое простых чисел последовательности.

    Напомним, что целое число называется простым, если оно делится нацело только на само себя и единицу. Подробно алгоритм определения простого числа описан в задаче 3.15 (рис. 3.29). В этой задаче кроме простых чисел фигурируют совершённые числа. Число называется совершённым, если сумма всех делителей, меньших его самого, равна этому числу. Алгоритм, с помощью которого можно определить делители числа, подробно рассмотрен в задаче 3.14 (рис. 3.28).

    Для решения поставленной задачи понадобятся две функции:

  • prostoe — определяет, является ли число простым, аргумент функции целое число $$N$$; функция возвращает 1, если число простое и 0 — в противном случае.;
  • soversh — определяет, является ли число совершённым; входной параметр целое число $$N$$; функция возвращает 1, если число является совершённым и 0 — в противном случае.
  • #include <iostream>
    #include <math.h>
    unsigned int prostoe ( unsigned int N) //Описание функции.
    {
    	//Функция определяет, является ли число простым.
    	int i, pr;
    	for ( pr =1, i =2; i<=N/ 2; i ++)
    	if (N%i ==0) { pr =0; break; }
    	return pr;
    }
    unsigned int soversh ( unsigned int N) //Описание функции.
    {
    	//Функция определяет, является ли число совершённым.
    	unsigned int i, S;
    	for ( S=0, i =1; i<=N/ 2; i ++)
    		if (N%i ==0) S+=i; //Сумма делителей.
    	if ( S==N) return 1;
    	else return 0;
    }
    using namespace std;
    int main ( )
    {
    	unsigned int i,N,X, S, kp, ks;
    	long int P;
    	cout <<"N="; cin >>N;
    	for ( kp=ks=S=0,P=1, i =1; i<=N; i ++)
    	{
    		cout <<"X="; cin >> X; //Вводится элемент последовательности.
    		if ( prostoe (X) ) // X — простое число.
    		{
    			kp++; //Счётчик простых чисел.
    			P*=X; //Произведение простых чисел.
    		}
    		if ( soversh (X) ) //X — совершённое число.
    		{
    			ks++; //Счётчик совершённых чисел.
    			S+=X; //Сумма совершённых чисел.
    		}
    	}
    	if ( kp>0) //Если счётчик простых чисел больше нуля,
    		//считаем среднее геометрическое и выводим его,
    		cout<<"Среднее геометрическое="<<pow(P, ( float ) 1/kp )<<endl;
    	else //в противном случае –– сообщение об отсутствии простых чисел.
    		cout<<"Нет простых чисел\n";
    	if ( ks>0) //Если счётчик совершённых чисел больше нуля,
    		//считаем среднее арифметическое и выводим его,
    		cout<<"Среднее арифметическое="<<(float ) S/ ks<<endl;
    	else //в противном случае — сообщение об отсутствии совершённых чисел.
    		cout<<"Нет совершённых чисел\n";
    	return 0;
    }
    		

    Задача 4.2. Вводится последовательность целых чисел, 0 — конец последовательности. Найти минимальное число среди простых чисел и максимальное — среди чисел, не являющихся простыми.

    Для решения данной задачи создадим функцию prostoe, которая будет проверять, является ли число $$N$$ простым. Входным параметром функции будет целое положительное число $$N$$. Функция будет возвращать значение 1, если число простое, и 0 — в противном случае. Алгоритм поиска максимума (минимума) подробно описан в задаче 3.20 (рис. 3.31).

    Текст программы:

    #include <iostream>
    using namespace std;
    unsigned int prostoe ( unsigned int N)
    {
    	int i, pr;
    	for ( pr =1, i =2; i>=N/ 2; i ++)
    	if (N%i ==0) { pr =0; break; }
    	return pr;
    }
    int main ( )
    {
    	int kp=0,knp=0,min, max,N;
    	for ( cout << "N=", cin >>N; N != 0; cout<<"N=", cin >>N)
    		//В цикле вводится элемент последовательности N.
    		if ( prostoe (N) ) //N — простое число,
    		{
    			kp++; //счётчик простых чисел.
    			if ( kp==1) min=N; //Предполагаем, что первое простое число минимально,
    			else if (N<min ) min=N; //если найдётся меньшее число, сохраняем его.
    		}
    		else //N — простым не является,
    		{
    			knp++; //счётчик чисел не являющихся простыми.
    			if ( knp==1) max=N; //Предполагаем, что первое не простое число максимально,
    			else if (N>max) max=N; //если найдётся большее число, сохраняем его.
    		}
    		if ( kp>0) //Если счётчик простых чисел больше нуля,
    			cout <<" min = "<<min<<"\t"; //выводим значение минимального простого числа,
    		else //в противном случае —
    			cout <<"Нет простых чисел"; //сообщение об отсутствии простых чисел.
    		if ( knp>0) //Если счётчик чисел не являющихся простыми больше нуля,
    			cout <<" max ="<<max<<endl; //выводим значение максимального числа,
    		else //в противном случае —
    			cout <<"Нет составных чисел"; //сообщение об отсутствии чисел
    			//не являющихся простыми.
    	return 0;
    }
    		

    Задача 4.3. Вводится последовательность из $$N$$ целых положительных чисел. В каждом числе найти наименьшую и наибольшую цифрыВыделение цифры из числа подробно описано в задаче 3.16.

    Программный код к задаче 4.3.

    #include <iostream>
    using namespace std;
    unsigned int Cmax( unsigned long long int P)
    {
    	unsigned int max;
    	if (P==0) max=0;
    	for ( int i =1; P!=0;P/=10)
    	{
    		if ( i ==1) {max=P%10; i ++;}
    		if (P%10>max) max=P%10;
    	}
    	return max;
    }
    unsigned int Cmin( unsigned long long int P)
    {
    	unsigned int min;
    	if (P==0) min=0;
    	for ( int i =1; P!=0;P/=10)
    	{
    		if ( i ==1) {min=P%10; i ++;}
    		if (P%10<min ) min=P%10;
    	}
    	return min;
    }
    int main ( )
    {
    	unsigned int N, k;
    	unsigned long long int X;
    	for ( cout<<"N=", cin >>N, k=1;k<=N; k++)
    	{
    		cout<<"X="; cin >>X;
    		cout<<"Максимальная цифра="<<Cmax(X);
    		cout<<" Минимальная цифра="<<Cmin(X)<<endl;
    	}
    	return 0;
    }
    		

    Задача 4.4. Вводится последовательность целых положительных чисел, 0 — конец последовательности. Определить, сколько в последовательности чисел-палиндромовПалиндром — любой симметричный относительно своей середины набор символов..

    Алгоритм определения палиндрома подробно описан в задаче 3.19. Далее приведён программный код к задаче 4.4

    #include <iostream>
    using namespace std;
    bool palindrom ( unsigned long long int N)
    { //Функция определяет, является ли число N палиндромом, возвращает true, если N —
    	//палиндром, и false в противном случае
    	unsigned long int M, R, S;
    	int kol, i;
    	for (R=1, kol =1,M=N;M/10>0; kol ++,R*=10,M/=10);
    	for ( S=0,M=N, i =1; i<=kol; S+=M%10*R,M/=10,R/=10, i ++);
    		if (N==S ) return true;
    		else return false;
    }
    int main ( )
    { unsigned long long int X;
    	int K;
    	for (K=0, cout<<"X=", cin >>X;X!=0; cout<<"X=", cin >>X)
    		if ( palindrom (X) ) K++;
    			cout<<"Количество палиндромов равно K="<<K<<endl;
    	return 0;
    }
    		

    Задача 4.5. Заданы два числа — $$X$$ в двоичной системе счисления, $$Y$$ в системе счисления с основанием пять. Найти сумму этих чисел. Результат вывести в десятичной системе счисления.

    Любое целое число $$N$$, заданное в $$b$$-ичной системе счисления, можно представить в десятичной системе счисления: $$N=P_n\cdot b^b+P_{n-1}\cdot b^{n-1}+...+P_2\cdot b^2+P_1\cdot b+P_0=\sum_{i=0}^n{P_i\cdot b^i},$$ где $$b$$ — основание системы счисления (целое положительное фиксированное число), $$P_i$$ — разряд числа: $$0\leqslant P_i\leqslant b-1,i=0,1,2,...,n.$$ Например,

    $$743_{10}=7\cdot 10^2+4\cdot 10^1+3\cdot 10^0=700+40+3=743_{10};\\ 1011101_2=1\cdot 2^6+0\cdot 2^5+1\cdot 2^4+1\cdot 2^3+1\cdot 2^2+0\cdot 2^1+1\cdot 2^0=64+16+8+4+1=93_{10}.$$

    Создадим функцию для перевода целого числа $$N$$, заданного в $$b$$-ичной системе счисления, в десятичную систему счисления.

    #include <iostream>
    using namespace std;
    unsigned long long int DecNC( unsigned long long int N, unsigned int b )
    {
    	//Функция выполняет перевод числа N, заданного в b-ичной системе счисления,
    	//в десятичную систему счисления
    	unsigned long long int S, P;
    	for ( S=0,P=1;N!=0; S+=N%10*P, P*=b,N/=10);
    	return S;
    }
    int main ( )
    {
    	unsigned long long int X,Y; unsigned int bX, bY;
    	cout<<"X="; cin >>X; //Ввод числа X.
    	cout<<"b="; cin >>bX; //Ввод основания с/с.
    	cout<<"Y="; cin >>Y; //Ввод числа X.
    	cout<<"b="; cin >>bY; //Ввод основания с/с.
    	//Вывод заданных чисел в десятичной с/с.
    	cout<<X<<"("<<bX<<")="<<DecNC(X, bX)<<" (10) "<<endl;
    	cout<<Y<<"("<<bY<<")="<<DecNC(Y, bY)<<" (10) "<<endl;
    	//Вычисление суммы и вывод результата.
    	cout<<X<<"("<<bX<<")+"<<Y<<"("<<bY<<")=";
    	cout<<DecNC(X, bX)+DecNC(Y, bY)<<" (10) "<<endl;
    	return 0;
    }
    		

    Задача 4.6. Задано число $$X$$ в десятичной системе счисления. Выполнить перевод числа в системы счисления с основанием 2, 5 и 7.

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

  • Разделить данное число на основание новой системы счисления: остаток от деления — младший разряд нового числа;
  • Если частное от деления не равно нулю, продолжать деление, как указано в п.1.
  • На рис. 4.1 приведён пример "ручного" перевода числа 256, заданного в десятичной системе счисления, в восьмеричную. В результате получим $$256_{(10)}=400_{(8)}$$

    (рис 4.1) Пример перевода числа в новую систему счисления

    Далее приведён текст программы, реализующей решение задачи 4.6.

    #include <iostream>
    using namespace std;
    unsigned long long int NC( unsigned long long int N, unsigned int b )
    {
    	unsigned long long int S, P;
    	for ( S=0,P=1;N!=0; S+=N%b *P, P*=10,N/=b );
    	return S;
    }
    int main ( )
    {
    	unsigned long long int X;
    	cout<<"X="; cin >>X; //Ввод числа X.
    	//Перевод числа X в заданные системы счисления.
    	cout<<X<<" (10) ="<<NC(X, 2 )<<" (2) "<<endl;
    	cout<<X<<" (10) ="<<NC(X, 5 )<<" (5) "<<endl;
    	cout<<X<<" (10) ="<<NC(X, 7 )<<" (7) "<<endl;
    	return 0;
    }
    		

    Задача 4.7. Найти корни уравнения $$x^2-\cos (5\cdot x)=0$$.

    Для решения задачи использовать:

  • метод половинного деления,
  • метод хорд,
  • метод касательных (метод Ньютона),
  • метод простой итерации.
  • Оценить степень точности предложенных численных методов, определив, за сколько итераций был найден корень уравнения. Вычисления проводить с точностью $$\varepsilon=10^{-3}$$.

    Вообще говоря, аналитическое решение уравнения $$f(x) = 0$$ можно найти только для узкого класса функций. В большинстве случаев приходится решать уравнение (4.1) численными методами. Численное решение уравнения (4.1) проводят в два этапа: сначала необходимо отделить корни уравнения, т.е. найти достаточно тесные промежутки, в которых содержится только один корень, эти промежутки называют интервалами изоляции корня; на втором этапе проводят уточнение отделённых корней, т.е. находят корни с заданной точностью.

    Интервал можно выделить, изобразив график функции, или каким-либо другим способом. Но все способы основаны на следующем свойстве непрерывной функции: если функция $$f (x)$$ непрерывна на интервале [$$a, b$$] и на его концах имеет различные знаки, $$f (a) \cdot f (b) < 0$$, то между точками имеется хотя бы один корень. Будем считать интервал настолько малым, что в нём находится только один корень. Рассмотрим самый простой способ уточнения корней.

    Графическое решение задачи 4.7 показано на рис. 4.2. Так как функция $$f(x)=x^2-\cos (5\cdot x)$$ дважды пересекает ось абсцисс, можно сделать вывод о наличии в уравнении $$x^2-\cos (5\cdot x)=0$$ двух корней. Первый находится на интервале [-0.4; -0.2], второй принадлежит отрезку [0.2; 0.4] .

    (рис 4.2) Геометрическое решение задачи 4.7

    Рассмотрим предложенные в задаче численные методы решения нелинейных уравнений.

    Метод половинного деления (дихотомии). Пусть был выбран интервал изоляции [$$a, b$$] (рис. 4.3). Примем за первое приближение корня точку c, которая является серединой отрезка [$$a, b$$].Далее будем действовать по следующему алгоритму:

  • Находим точку $$c=\frac{a+b}{2}$$;
  • Находим значение $$f (c)$$;
  • Если $$f(a)\cdot f(c)<0$$, то корень лежит на интервале [$$a, c$$], иначе корень лежит на интервале [$$c, b$$];
  • Если величина интервала меньше либо равна $$\varepsilon$$, то найден корень с точностью $$\varepsilon$$, иначе возвращаемся к п.1.
  • Итак, для вычисления одного из корней уравнения $$ x^2-\cos (5\cdot x)=0$$ методом половинного деления достаточно знать интервал изоляции корня $$a=0.2;b=0.4$$ и точность вычисления $$\varepsilon=10^{-3}$$.

    Блок-схема алгоритма решения уравнения методом дихотомии приведена на рис. 4.4. Понятно, что здесь $$c$$ — корень заданного уравнения.

    Однако, несмотря на простоту, такое последовательное сужение интервала проводится редко, так как требует слишком большого количества вычислений.

    (рис 4.3) Графическая интерпретация метода половинного деления

    Кроме того, этот способ не всегда позволяет найти решение с заданной точностью. Рассмотрим другие способы уточнения корня. При применении этих способов будем требовать, чтобы функция $$f (x)$$ удовлетворяла следующим условиям на интервале [$$a, b$$] :

  • функция $$f (x)$$ непрерывна вместе со своими производными первого и второго порядка. Функция $$f (x)$$ на концах интервала [$$a, b$$] имеет разные знаки $$f(a)\cdot f(b)<0$$;
  • первая и вторая производные $$f'(x)$$ и $$f''(x)$$ сохраняют определённый знак на всём интервале [$$a, b$$] .
  • Метод хорд. Этот метод отличается от метода дихотомии тем, что очередное приближение берём не в середине отрезка, а в точке пересечения с осью $$X$$ (рис. 4.5) прямой, соединяющей точки ($$a, f (a)$$) и ($$b, f (b)$$).

    Запишем уравнение прямой, проходящей через точки с координатами ($$a, f (a)$$) и ($$b, f (b)$$) : $$\frac{y-f(a)}{f(b)-f(a)}=\frac{x-a}{b-a},\ \ \ y=\frac{f(b)-f(a)}{b-a}\cdot (x-a)+f(a)$$

    Прямая, заданная уравнением (4.2), пересекает ось $$X$$ при условии $$y = 0$$.

    Найдём точку пересечения хорды с осью $$X$$: $$y=\frac{f(b)-f(a)}{b-a}\cdot (x-a)+f(a),\ \ x=a-\frac{f(a)\cdot (b-a)}{f(b)-f(a)}.$$ итак, $$c=a-\frac{f(a)}{f(b)-f(a)}(b-a)$$.

    Далее необходимо вычислить значение функции в точке $$c$$. Это и будет приближённое значение корня уравнения.

    (рис 4.4) Алгоритм решения уравнения методом дихотомии

    Для вычисления одного из корней уравнения $$x^2-\cos (5\cdot x)=0$$ методом хорд достаточно знать интервал изоляции корня, например, $$a = 0.2; b = 0.4$$, и точность вычисления $$\varepsilon=10^{-3}$$. Блок-схема метода представлена на рис. 4.6.

    Метод касательных (метод Ньютона). В одной из точек интервала [$$a; b$$], пусть это будет точка $$a$$, проведём касательную (рис. 4.7). Запишем уравнение этой прямой:$$y=k\cdot x+m$$

    Так как эта прямая является касательной, и она проходит через точку $$(c,f(c))$$, то $$k=f'(c)$$.

    Следовательно, $$y=f'(x)\cdot x+m,f(c)=f'(c)\cdot c+m,m=f(c)-c\cdot f'(c),\\y=f'(c)\cdot x+f(c)-c\cdot f'(c),y=f'(c)\cdot (x-c)+f(c)$$.

    Найдём точку пересечения касательной с осью $$X$$: $$f'(c)\cdot (x-c)+f(c)=0,\ \ x=c-\frac{f(c)}{f'(c)}$$

    (рис 4.5) Графическая интерпретация метода хорд

    Если $$|f(x)|<\varepsilon$$, то точность достигнута, и точка $$x$$ — решение; иначе необходимо переменной c присвоить значение $$x$$ и провести касательную через новую точку $$c$$; так продолжать до тех пор, пока $$|f (x)|$$ не станет меньше $$\varepsilon$$. Осталось решить вопрос, что выбрать в качестве точки начального приближения $$c$$.

    В этой точке должны совпадать знаки функции и её второй производной. А так как нами было сделано допущение, что вторая и первая производные не меняют знак, то можно проверить условие $$f(x)\cdot f''(x)>0$$ на обоих концах интервала, и в качестве начального приближения взять ту точку, где это условие выполняется.

    Здесь, как и в предыдущих методах, для вычисления одного из корней уравнения $$x^2-\cos (5\cdot x)=0$$ достаточно знать интервал изоляции корня, например, $$a = 0.2; b = 0.4$$, и точность вычисления $$\varepsilon=10^{-3}$$. Блок-схема метода Ньютона представлена на рис. 4.8. Понятно, что для реализации этого алгоритма нужно найти первую и вторую производные функции $$f(x)=x^2-\cos (5\cdot x): f'(x)=2\cdot x+5\cdot \sin (5\cdot x), f(x) =2 +25 \cdot cos(5 \cdot x)$$.

    Метод простой итерации. Для решения уравнения этим методом необходимо записать уравнение (4.1) в виде $$x=\phi(x)$$, задать начальное приближение $$x_0\in [a;b]$$ и организовать следующий итерационный вычислительный процесс: $$x_{k+1}=\phi(x_k),k=0,1,2,...$$

    Вычисление прекратить, если $$|x_{k+1}-x_k|<\varepsilon$$ ($$\varepsilon$$ — точность).

    Если неравенство $$|\phi'(x)|<1$$ выполняется на всём интервале [$$a; b$$], то последовательность $$x_0, x_1, x_2,...,x_n,... , ...$$ сходится к решению $$x^*$$ (т.е. l$$\lim\limits_{k\rightarrow \infty}x_k=x^*$$).

    Значение функции $$\phi(x)$$ должно удовлетворять условию $$|\phi'(x)|<1$$ для того, чтобы можно было применить метод простых итераций. Условие $$|\phi'(x)|<1$$ является достаточным условием сходимости метода простой итерации.

    (рис 4.6) Алгоритм метода хорд

    Уравнение (4.1) можно привести к виду $$x=\phi(x)$$ следующим образом. Умножить обе части уравнения $$f (x) = 0$$ на число $$\lambda$$. К обеим частям уравнения $$\lambda\cdot f(x)=0$$ добавить число $$x$$. Получим $$x=x+\lambda\cdot f(x)$$. Это и есть уравнение вида $$x=\phi(x)$$, где

    $$\phi(x)=x+\lambda\cdot f(x)$$

    Необходимо чтобы неравенство $$|\phi"(x)|<1$$ выполнялось на интервале [$$a; b$$], следовательно, $$|\phi"(x)|=|1+\lambda\cdot f'(x)|$$ и $$|1+\lambda\cdot f'(x)|<1 (|1+\lambda\cdot f'(a)|<1, |1+\lambda\cdotf'(b)|<1)$$, а значит, с помощью подбора параметра $$\lambda$$ можно добиться выполнения условия сходимости.

    Для вычисления корней уравнения $$x^2-\cos (5\cdot x)=0$$ воспользуемся графическим решением (рис. 4.2) и определим интервал изоляции одного из корней, например, $$a = 0.2; b = 0.4$$. Подберём значение $$\lambda$$, решив неравенство $$|1+\lambda\cdot f'(x)|<1:|1+\lambda\cdot f'(a)|<1$$ и $$|1+\lambda\cdot f'(b)|<1,\\f(x)=x^{2}-\cos (5\cdot x),f'(x)=2\cdot x+5\cdot \sin (5\cdot x),\\f'(a)=2\cdot 0.2+5\cdot \sin (5\cdot 0.2)\approx 4.6, f'(b)=2\cdot 0.4+5\cdot \sin (5\cdot 0.4)\approx 5.35,\\|1+\lambda\cdot 4.6|<1$$ и $$|1+\lambda\cdot 5.35|<1$$. $$\left\{\begin{array}{l} \left\{\begin{array}{l} 1+4.6\cdot \lambda<1 \cr 1+4.6\cdot \lambda>-1 \end{array}\right.\cr \left\{\begin{array}{l} \lambda<0 \cr \lambda>-0.37 \end{array}\right. \end{array}\right. \Rightarrow \left\{\begin{array}{l} \left\{\begin{array}{l} \lambda<0 \cr \lambda>-0.4 \end{array}\right.\cr \left\{\begin{array}{l} \lambda<0 \cr \lambda>-0.37 \end{array}\right. \end{array}\right. \Rightarrow \left\{\begin{array}{l} \lambda\in (-0.4;0) \cr \lambda\in (-0.37;0) \end{array}\right.$$

    и, следовательно, $$\lambda\in (-0.37;0)$$.

    (рис 4.7) Графическая интерпретация метода касательных

    Таким образом, исходными данными для программы будут начальное значение корня уравнения $$x_0=0.2$$, значение параметра $$\lambda$$ (пусть $$\lambda= -0.2$$), и точность вычислений $$\varepsilon=0.001$$.

    Для вычисления второго корня заданного уравнения параметр $$\lambda$$ подбирают аналогично.

    Блок-схема метода простой итерации приведена на рис. 4.9.

    Далее представлен текст программы, реализующий решение задачи 4.7.

    #include <iostream>
    #include <math.h>
    using namespace std;
    //Функция, определяющая левую часть уравнения f (x) = 0.
    double f ( double x )
    {
    	return ( x *x-cos (5 * x ) );
    }
    //Функция, реализующая метод половинного деления.
    int Dichotomy ( double a, double b, double * c, double eps )
    { int k=0;
    	do
    	{
    		* c=(a+b ) / 2;
    		if ( f ( * c ) * f ( a ) <0) b=*c;
    		else a=*c;
    		k++;
    	}
    	while ( fabs ( a-b )>=eps );
    	return k;
    }
    //Функция, реализующая метод хорд.
    int Chord ( double a, double b, double * c, double eps )
    { int k=0;
    	do
    	{
    		* c=a-f ( a ) /( f ( b )-f ( a ) ) * ( b -a );
    		if ( f ( * c ) * f ( a ) >0) a=*c;
    		else b=*c;
    		k++;
    	}
    	while ( fabs ( f ( * c ) )>=eps );
    	return k;
    }
    double f1 ( double x ) //Первая производная функции f (x).
    {
    	return (2 * x+5* sin (5 * x ) );
    }
    double f2 ( double x ) //Вторая производная функции f (x).
    {
    	return (2+25* cos (5 * x ) );
    }
    //Функция, реализующая метод касательных.
    int Tangent ( double a, double b, double * c, double eps )
    { int k=0;
    	if ( f ( a ) * f2 ( a ) >0) * c=a;
    	else * c=b;
    	do
    	{
    		* c=*c-f (* c ) / f1 ( * c );
    		k++;
    	}
    	while ( fabs ( f ( * c ) )>=eps );
    	return k;
    }
    double fi ( double x, double L) //Функция, заданная выражением 4.4 .
    {
    	return ( x+L* f ( x ) );
    }
    //Функция, реализующая метод простой итерации.
    int Iteration ( double *x, double L, double eps )
    { int k=0; double x0;
    	do
    	{
    		x0=*x;
    		*x= fi(x0, L);
    		k++;
    	}
    	while ( fabs ( x0-*x )>=eps );
    	return k;
    }
    int main ( )
    {
    	double A, B, X, P;
    	double ep =0.001; //Точность вычислений.
    	int K;
    	cout<<"a="; cin >>A; //Интервал изоляции корня.
    	cout<<"b="; cin >>B;
    	cout<<"Решение уравнения x^2 - cos (5* x) =0. "<<endl;
    	cout<<"Метод дихотомии:"<<endl;
    	K=Dichotomy (A, B,X, ep );
    	cout<<"Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	cout<<"Метод хорд:"<<endl;
    	K=Chord (A, B,X, ep );
    	cout<<" Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	cout<<"Метод касательных:"<<endl;
    	K=Tangent (A, B,X, ep );
    	cout<<" Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	cout<<"Метод простой итерации:"<<endl;
    	X=A;
    	cout<<"L="; cin >>P;
    	K=Iteration (X, P, ep );
    	cout<<" Найденное решение x="<<X;
    	cout<<", количество итераций k="<<K<<endl;
    	return 0;
    }
    				
    (рис 4.8) Алгоритм метода Ньютона (рис 4.9) Алгоритм метода простой итерации

    Результаты работы программы:

    a=0.2
    b=0.4
    Решение уравнения x^2-cos(5*x)=0.
    Метод дихотомии:
    Найденное решение x=0.296094, количество итераций k=8
    Метод хорд:
    Найденное решение x=0.296546, количество итераций k=2
    Метод касательных:
    Найденное решение x=0.296556, количество итераций k=2
    Метод простой итерации:
    L=-0.2
    Найденное решение x=0.296595, количество итераций k=3
    				

    4.5 Рекурсивные функции

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

    Рассмотрим применение рекурсии на примерах [7, 8].

    Задача 4.8. Вычислить факториал числа $$n$$.

    Вычисление факториала подробно рассмотрено в задаче 3.12 (рис. 3.25). Для решения этой задачи с применением рекурсии создадим функцию factoial, алгоритм которой представлен на рис. 4.10.

    (рис 4.10) Рекурсивный алгоритм вычисления факториала

    Текст программы с применением рекурсии:

    #include <iostream>
    using namespace std;
    long int factorial ( int n )
    {
    	if ( n<=1)
    	return n;
    	else
    	return n*factorial ( n-1);
    }
    int main ( )
    {
    	int i; long int f;
    	cout<<"i="; cin >>i;
    	f=factorial ( i );
    	cout<<i <<" !="<<f<<"\n";
    	return 0;
    }
    				

    Задача 4.9. Вычислить $$n$$-ю степень числа $$a$$ ($$n$$ — целое число).

    Результатом возведения числа $$a$$ в целую степень $$n$$ является умножение этого числа на себя $$n$$ раз. Но это утверждение верно только для положительных значений $$n$$. Если $$n$$ принимает отрицательные значения, то $$a^{-n}=\frac{1}{a^n}$$.В случае $$n=0,\ \ a^0=1$$.

    Для решения задачи создадим рекурсивную функцию stepen, алгоритм которой представлен на рис. 4.11.

    (рис 4.11) Рекурсивный алгоритм вычисления степени числа

    Текст программы с применением рекурсии:

    #include <iostream>
    using namespace std;
    float stepen ( float a, int n )
    {
    	if ( n==0)
    		return 1;
    	else if ( n<0)
    		return 1/ stepen ( a,-n );
    	else
    	return a * stepen ( a, n-1);
    }
    int main ( )
    {
    	int i; float s, b;
    	cout<<"b="; cin >>b;
    	cout<<"i="; cin >>i;
    	s=stepen ( b, i );
    	cout<<"s="<<s<<"\n";
    	return 0;
    }
    				

    Задача 4.10. Вычислить $$n$$-е число Фибоначчи.

    Если нулевой элемент последовательности равен нулю, первый — единице, а каждый последующий представляет собой сумму двух предыдущих, то это последовательность чисел Фибоначчи (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ... ).

    Алгоритм рекурсивной функции fibonachi изображён на рис. 4.12.

    (рис 4.12) Рекурсивный алгоритм вычисления числа Фибоначчи

    Текст программы:

    #include <iostream>
    using namespace std;
    long int fibonachi ( unsigned int n )
    {
    	if ( ( n==0) | | ( n==1))
    	return n;
    	else
    	return fibonachi ( n -1)+fibonachi ( n-2);
    }
    int main ( )
    {
    	int i; long int f;
    	cout<<"i="; cin >>i;
    	f=fibonachi ( i );
    	cout<<"f="<<f<<"\n";
    	return 0;
    }
    				

    4.6 Перегрузка функций

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

    В приведённом далее тексте программы три функции с именем Pow. Первая выполняет операцию возведения вещественного числа $$a$$ в дробную степень $$n=\frac{k}{m}$$, где $$k$$ и $$m$$ — целые числа. Вторая возводит вещественное число $$a$$ в целую степень $$n$$, а третья — целое число $$a$$ в целую степень Как известно, операция $$a^n$$ не определена при $$a = 0$$ и $$n = 0$$, а так же при возведении отрицательного значения $$a$$ в дробную степень $$n=\frac{k}{m}$$, где $$m$$ — чётное число (п. 2.7).Пусть наши функции в этих случаях возвращают 0. $$n$$. Какую именно функцию вызвать компилятор определяет по типу фактических параметров. Так, если $$a$$ — вещественное число, а $$k$$ — целое, то оператор Pow(a,k) вызовет вторую функцию, так как она имеет заголовок float Pow(float a, int n). Команда Pow((int)a,k) приведёт к вызову третьей функции float Pow(int a, int n), так как вещественная переменная $$a$$ преобразована к целому типу. Первая функция float Pow(float a, int k, int m) имеет три параметра, значит, обращение к ней осуществляется командой Pow(a,k,m).

    #include <iostream>
    using namespace std;
    #include <math.h>
    float Pow( float a, int k, int m) //Первая функция
    {
    	cout<<"Функция 1 \t";
    	if ( a==0)
    	return 0;
    	else if ( k==0)
    	return 1;
    	else if ( a>0)
    	return exp ( ( float ) k/m *log ( a ) );
    	else if (m%2!=0)
    	return -(exp ( ( float ) k/m *log (-a ) ) );
    }
    float Pow( float a, int n ) //Вторая функция
    {
    	float p; int i;
    	cout<<"Функция 2 \t";
    	if ( a==0)
    		return 0;
    	else if ( n==0)
    		return 1;
    	else if ( n<0)
    	{
    		n= -n;
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return ( float ) 1/p;
    	}
    	else
    	{
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return p;
    	}
    }
    float Pow( int a, int n ) //Третья функция
    {
    	int i, p;
    	cout<<"Функция 3 \t";
    	if ( a==0)
    		return 0;
    	else if ( n==0)
    		return 1;
    	else if ( n<0)
    	{
    		n= -n;
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return ( float ) 1/p;
    	}
    	else
    	{
    		p=1;
    		for ( i =1; i<=n; i ++)
    		p*=a;
    		return p;
    	}
    }
    int main ( )
    {
    	float a; int k, n,m;
    	cout<<"a="; cin >>a;
    	cout<<"k="; cin >>k;
    	cout<<"s="<<Pow( a, k )<<"\n"; //Вызов 2-й функции.
    	cout<<"s="<<Pow ( ( int ) a, k )<<"\n"; //Вызов 3-й функции.
    	cout<<"a="; cin >>a;
    	cout<<"k="; cin >>k;
    	cout<<"m="; cin >>m;
    	cout<<"s="<<Pow( a, k,m)<<endl; //Вызов 1-й функции.
    	return 0;
    }
    				

    Результаты работы программы:

    a=5.2
    k=3
    Функция 2 s=140.608
    Функция 3 s=125
    a=-8
    k=1
    m=1
    Функция 1 s=-8
    a=5.2
    k=-3
    Функция 2 s=0.00711197
    Функция 3 s=0.008
    a=-8
    k=1
    m=3
    Функция 1 s=-2
    				

    4.7 Шаблоны функций

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

    Простейшую функцию–шаблон в общем виде можно записать так [6]:

    template <class Type> заголовок
    {
    	тело функции
    }
    				

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

    Рассмотрим пример шаблона поиска наименьшего из четырёх чисел.

    #include <iostream>
    using namespace std;
    //Определяем абстрактный тип данных с помощью служебного слова Type .
    template <class Type>
    Type minimum( Type a, Type b, Type c, Type d )
    { //Определяем функцию с использованием типа данных Type .
    	Type min=a;
    	if ( b<min ) min=b;
    	if ( c<min ) min=c;
    	if ( d<min ) min=d;
    	return min;
    }
    int main ( )
    {
    	int ia, ib, ic, id, mini; float ra, rb, rc, rd, minr;
    	cout<<" Vvod 4 thelih chisla \t";
    	cin >>ia >>ib>>ic >>id;
    	mini=minimum( ia, ib, ic, id ); //Вызов функции minimum, в которую передаём
    	//4 целых значения.
    	cout<<"\n"<<mini<<"\n";
    	cout<<" Vvod 4 vecshestvenih chisla \t"; cin >>ra>>rb>>rc>>rd;
    	minr=minimum( ra, rb, rc, rd ); //Вызов функции minimum, в которую передаём
    	//4 вещественных значения.
    	cout<<"\n"<<minr<<"\n";
    	return 0;
    }
    				

    4.8 Область видимости переменных в функциях

    Как известно (п. 2.8), по месту объявления переменные в языке C++ делятся на три класса: локальные, глобальные и переменные, описанные в списке формальных параметров функций. Все эти переменные имеют разную область видимости.

    Локальные переменные объявляются внутри функции и доступны только в ней. О таких переменных говорят, что они имеют локальную видимость, то есть, видимы только внутри функции.

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

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

    Из функции, где действует локальное описание переменной, можно обратиться к глобальной переменной с таким же именем, используя оператор расширения области видимости

    ::переменная;
    				

    Рассмотрим пример:

    #include <iostream>
    using namespace std;
    float pr =100.678; //Переменная pr определена глобально.
    int prostoe ( int n )
    {
    	int pr =1, i; //Переменная pr определена локально.
    	if ( n<0) pr =0;
    	else
    	for ( i =2; i<=n / 2; i ++)
    		if ( n%i ==0){ pr =0; break; }
    			cout<<" local pr="<<pr<<"\n"; //Вывод локальной переменной.
    	cout<<" global pr=" <<::pr<<"\n"; //Вывод глобальной переменной.
    	return pr;
    }
    int main ( )
    {
    	int g;
    	cout<<"g="; cin >>g;
    	if ( prostoe ( g ) ) cout<<"g - prostoe \n";
    	else cout<<"g - ne prostoe \n";
    	return 0;
    }
    				

    Результаты работы программы:

    	g=7
    	local pr=1 //Локальная переменная.
    	global pr=100.678 //Глобальная переменная.
    	g - prostoe
    				

    4.9 Функция main(). Параметры командной строки

    Итак, любая программа на C++ состоит из одной или нескольких функций, причём одна из них должна обязательно носить имя main (основной, главный ). Именно этой функции передаётся управление после запуска программы. Как любая функция, main может принимать параметры и возвращать значения. У функции main две формы записи:

  • без параметров:
    тип main ( ) {тело функции },
    				
  • и с двумя параметрами:
    тип main ( int argc, char *argv [ ] ) {тело функции }
    				
    .
  • Первый параметр argc определяет количество параметров, передаваемых в функцию main из командной строки. Второй параметр argv — указатель на массив указателей типа char (массив строк). Каждый элемент массива ссылается на отдельный параметр командной строки. При стандартном запуске программы argc равно 1, argv — массив из одного элемента, этим элементом является имя запускаемого файла.

    Рассмотрим следующую программу.

    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    int main ( int argc, char * argv [ ] )
    {
    	int i;
    	cout<<"В командной строке "<<argc<<" аргументов\n";
    	for ( i =0; i <argc; i ++)
    	cout<<"Аргумент № "<<i <<" "<<argv [ i ]<<endl;
    	return 0;
    }
    				

    Текст программы хранится в файле 1.cpp. При стандартном запуске программа выведет следующую информацию:

    В командной строке 1 аргументов
    Аргумент № 0 ./1
    				

    Программа выводит количество параметров командной строки и последовательно все параметры. При стандартном запуске – количество аргументов командной строки — 1, этим параметром является имя запускаемого файла (в нашем случае, имя запускаемого файла — ./1).

    Запустим программу следующим образом:

    ./1 abc 34 6 + 90 Вася Маша
    				

    Результаты работы программы представлены ниже.

    В командной строке 8 аргументов
    Аргумент № 0 ./1
    Аргумент № 1 abc
    Аргумент № 2 34
    Аргумент № 3 6
    Аргумент № 4 +
    Аргумент № 5 90
    Аргумент № 6 Вася
    Аргумент № 7 Маша
    				

    Рассмотрим приложение, в которое в качестве параметров командной строки передаётся число1, операция, число2. Функция выводит

    число1 операция число2.
    				

    Текст программы приведён на нижеФункция atof преобразовывает строку символов в вещественное число, а если преобразование невозможно, то результатом функции atof будет число 0.0. Функция strcmp сравнивает две строки и возвращает 0 в случае совпадения строк. Подробнее об этих функциях можно прочесть в главе, посвящённой строкам.

    #include <iostream>
    #include <stdlib.h>
    #include <cstring>
    using namespace std;
    int main ( int argc, char **argv )
    {
    	//Если количество параметров больше или равно 4, то были введены два числа и знак операции.
    	if ( argc >=4)
    	//Если операция *, то выводим число1*число2.
    	{
    		if ( ! strcmp ( argv [ 2 ], "*" ) ) cout<<atof ( argv [ 1 ] ) * atof ( argv [ 3 ] )<<endl;
    		else
    		//Если операция +, то выводим число1+число2.
    		if ( ! strcmp ( argv [ 2 ], "+" ) ) cout<<atof ( argv [ 1 ] )+atof ( argv [ 3 ] )<<endl;
    		else
    		//Если операция -, то выводим число1-число2.
    		if ( ! strcmp ( argv [ 2 ], " -" ) ) cout<<atof ( argv [ 1 ] ) -atof ( argv [ 3 ] )<<endl;
    		else
    		//Если операция /, то выводим число1/число2.
    		if ( ! strcmp ( argv [ 2 ], "/" ) ) cout<<atof ( argv [ 1 ] ) / atof ( argv [ 3 ] )<<endl;
    		else cout<<"неправильный знак операции"<<endl;
    	}
    	else
    	cout<<"недостаточное количество операндов"<<endl;
    	return 0;
    }
    				

    Ниже приведены варианты запуска программы и результаты её работыТекст программы хранится в файле 4.cpp. Имя исполняемого файла ./4 (ОС Lnux). Предлагаем читателю самостоятельно разобраться с результатами всех тестовых запусков приложения.

    ./4 1.3 + 7.8
    9.1
    ./4 1.3 - 7.8
    -6.5
    ./4 1.3 / 7.8
    0.166667
    ./4 1.3 \* 7.8
    10.14
    ./4 1.3 % 7.8
    неправильный знак операции
    ./4 1.3+ 7.8
    недостаточное количество операндов
    				

    4.10 Задачи для самостоятельного решения

    4.10.1 Применение функций при работе с последовательностями чисел

    Разработать программу на языке C++ для следующих заданий:

  • Вводится последовательность целых положительных чисел, 0 — конец последовательности. Для каждого элемента последовательности определить и вывести на экран число, которое получится после записи цифр исходного числа в обратном порядке.
  • Вводится последовательность целых чисел, 0 — конец последовательности. Определить, содержит ли последовательность хотя бы одно совершённое число. Совершённое число равно сумме всех своих делителей, не превосходящих это число. Например, 6 = 1 + 2 + 3 или 28 = 1 + 2 + 4 + 7 + 14.
  • Вводится последовательность из N целых положительных элементов. Определить, содержит ли последовательность хотя бы одно простое число. Простое число не имеет делителей, кроме единицы и самого себя.
  • Вводится последовательность из $$N$$ целых положительных элементов. Посчитать количество чисел-палиндромов. Числа-палиндромы симметричны относительно своей середины, например, 12021 или 454.
  • Вводится последовательность из $$N$$ целых положительных элементов. Подсчитать количество совершённых и простых чисел в последовательности.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Определить, в каком из чисел больше всего делителей.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Определить, в каком из чисел больше всего цифр.
  • Вводится последовательность из $$N$$ целых положительных элементов. Проверить, содержит ли последовательность хотя бы одну пару соседних дружественных чисел. Два различных натуральных числа являются дружественными, если сумма всех делителей первого числа (кроме самого числа) равна второму числу. Например, 220 и 284, 1184 и 1210, 2620 и 2924, 5020 и 5564.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Каждый элемент последовательности представляет собой номер m одного из чисел Фибоначчи. Вычислить и вывести на экран m-е число Фибоначчи. Напомним, что в последовательности Фибоначчи каждое последующее число представляет собой сумму двух предыдущих (0, 1, 1, 2, 3, 5, 8, 13, 21, 34,...). Например, четвёртое число Фибоначчи равно 3, седьмое — 13, а девятое — 34.
  • Вводится последовательность из $$N$$ целых положительных элементов. Найти число с минимальным количеством цифр.
  • Вводится последовательность из$$ N$$ целых элементов. Для всех положительных элементов последовательности вычислить значение факториала. Вывести на экран число и его факториал.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Вывести на экран все числа последовательности, являющиеся составными и их делители. Составное число имеет более двух делителей, то есть не является простым.
  • Вводится последовательность из $$N$$ целых положительных элементов. Определить, содержит ли последовательность хотя бы одно число Армстронга. Число Армстронга — натуральное число, которое равно сумме своих цифр, возведённых в степень, равную количеству его цифр. Например, десятичное число 153 — число Армстронга, потому что: 13+ 33+ 53=1 + 27 + 125 = 153.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Найти среднее арифметическое простых чисел в этой последовательности. Простое число не имеет делителей, кроме единицы и самого себя.
  • Вводится последовательность из $$N$$ целых положительных элементов. Определить, сколько в последовательности пар соседних взаимно простых чисел. Различные натуральные числа являются взаимно простыми, если их наибольший общий делитель равен единице.
  • В последовательности из $$N$$ целых положительных элементов найти сумму всех недостаточных чисел. Недостаточное число всегда больше суммы всех своих делителей за исключением самого числа.
  • Вводится последовательность из $$N$$ целых положительных элементов. Посчитать количество элементов последовательности, имеющих в своём представлении цифру 0.
  • Вводится $$N$$ пар целых положительных чисел $$a$$ и $$b$$. В случае, если $$a > b$$ вычислить: $$C=\frac{a!}{b!\cdot (a-b)!}$$.
  • Вводится последовательность из $$N$$ целых элементов. Для каждого элемента последовательности найти среднее значение его цифр.
  • Вводится последовательность целых положительных чисел, 0 — конец последовательности. Для каждого элемента последовательности определить и вывести на экран число, которое получится, если поменять местами первую и последнюю цифры исходного числа.
  • Вводится последовательность из $$N$$ целых элементов. Для каждого элемента последовательности вывести на экран количество цифр и количество делителей.
  • Вводится последовательность из $$N$$ целых положительных элементов. Среди элементов последовательности найти наибольшее число-палиндром. Числа-палиндромы симметричны относительно своей середины, например, 12021 или 454.
  • Поступает последовательность целых положительных чисел, 0 — конец последовательности. Для каждого элемента последовательности вывести на экран сумму квадратов его цифр.
  • Вводится последовательность из $$N$$ целых положительных элементов. Для простых элементов последовательности определить сумму цифр. Простое число не имеет делителей, кроме единицы и самого себя.
  • Вводится последовательность целых положительных чисел, 0 — конец последовательности. Среди элементов последовательности найти наименьшее составное число. Составное число имеет более двух делителей, то есть не является простым.
  • 4.10.2 Применение функций для вычислений в различных системах счисления

    Разработать программу на языке C++ для решения следующей задачи. Заданы два числа — $$A$$ и $$B$$, первое в системе счисления с основанием $$p$$, второе в системе счисления с основанием $$q$$. Вычислить значение $$C$$ по указанной формуле и вывести его на экран в десятичной системе счисления и системе счисления с основанием $$r$$. Исходные данные для решения задачи представлены в табл. 4.1.

    Задания для решения задачи о различных системах счисления
    Вариант p q C r
    1 2 8 $$A^{2}\cdot (A+B)$$ 3
    2 3 4 $$2\cdot (A^{2}+B^{2})$$ 4
    3 4 6 $$2\cdot B^{2}\cdot (A+B)$$ 5
    4 5 2 $$(A-B)^{2}+3\cdot A$$ 6
    5 6 4 $$A^{2}+A\cdot B$$ 7
    6 7 3 $$(5\cdot B-2\cdot A)^{2}$$ 8
    7 8 2 $$(2\cdot A-3\cdot B)^{2}$$ 5
    8 3 8 $$(B-A)^{2}+2\cdot A$$ 6
    9 4 7 $$B^{3}-B^{2}+2\cdot A$$ 2
    10 5 6 $$A^{3}-A^{2}+3\cdot B$$ 8
    11 6 5 $$(2\cdot A-3\cdot B)^{2}$$ 3
    12 7 4 $$A^{2}+2\cdot A+B^{2}$$ 5
    13 8 3 $$A^{2}+3\cdot B+B^{2}$$ 7
    14 4 2 $$A^{2}-2\cdot A+B$$ 6
    15 5 8 $$3\cdot B^{2}-2\cdot B+A$$ 3
    16 6 7 $$A^{2}+(B-A)^{2}$$ 2
    17 7 6 $$3\cdot B^{2}+2\cdot A\cdot B$$ 8
    18 8 5 $$2\cdot A^{2}+3\cdot A\cdot B$$ 7
    19 2 4 $$B^{3}-2\cdot B+A$$ 3
    20 3 8 $$A^{3}-2\cdot A+B$$ 4
    21 4 7 $$(5\cdot A-2\cdot B)^{2}$$ 5
    22 5 6 $$(B^{2}-3\cdot A)^{2}$$ 7
    23 6 5 $$(A^{2}-2\cdot B)^{2}$$ 8
    24 7 4 $$A^{2}\cdot B^{2}-A\cdot B$$ 6
    25 8 3 $$A\cdot B+A^{2}-B$$ 2

    4.10.3 Применение функций для решения нелинейных уравнений

    Разработать программу на языке C++ для вычисления одного из корней уравнения $$f (x) = 0$$ методами, указанными в задании. Для решения задачи предварительно определить интервал изоляции корня графическим методом. Вычисления проводить с точностью $$\varepsilon=10^{-4}$$. Оценить степень точности путём подсчёта количества итераций, выполненных для достижения заданной точности. Исходные данные для решения задачи представлены в табл. 4.2.

    Задания к задаче о решении нелинейных уравнений
    Уравнение f (x) = 0 Методы решения
    1 $$x-0.2\cdot \sin (x+0.5)=0$$ метод половинного деления, метод хорд
    2 $$x^2-\lg(x+2)=0$$ метод касательных, метод простой итерации
    3 $$x^2-20\cdot \sin (x)=0$$ метод хорд, метод касательных
    4 $$\ln (x)+(x+1)^3=0$$ метод дихотомии, метод простой итерации
    5 $$x^2-\sin(5x)=0$$ метод половинного деления, метод касательных
    6 $$e^x+x^2-2=0$$ метод хорд, метод простой итерации
    7 $$0.8\cdot x^{2}-\sin (10\cdot x)=0$$ метод половинного деления, метод хорд
    8 $$\sin (7\cdot x)+2\cdot x-6=0$$ метод касательных, метод простой итерации
    9 $$x\cdot \ln (x)-1=0$$ метод хорд, метод касательных
    10 $$2\cdot \lg(x)+0.5\cdot x=0$$ метод дихотомии, метод простой итерации
    11 $$e^{-x}-x^2=0$$ метод половинного деления, метод касательных
    12 $$x^2-3\cdot \cos (x^2)=0$$ метод хорд, метод простой итерации
    13 $$\sin (7\cdot x)-x^2+15=0$$ метод половинного деления, метод хорд
    14 $$(x-1)^2-0.5\cdot e^x=0$$ метод касательных, метод простой итерации
    15 $$2\cdot \ln (x)-0.2\cdot x+1=0$$ метод хорд, метод касательных
    16 $$2-x\cdot e^x=0$$ метод дихотомии, метод простой итерации
    17 $$0.1\cdot x^3+3\cdot x^2-10\cdot x-7=0$$ метод половинного деления, метод касательных
    18 $$0.1\cdot x^2-e^x=0$$ метод хорд, метод простой итерации
    19 $$e^{-2\cdot x}-2\cdot x+1=0$$ метод половинного деления, метод хорд
    20 $$x^2-3+0.5^x=0$$ метод касательных, метод простой итерации
    21 $$\lg(4\cdot x)-\cos (x)=0$$ метод хорд, метод касательных
    22 $$\ln(x)-\cos^2(x)=0$$ метод дихотомии, метод простой итерации
    23 $$\frac{4}{x}-0.2\cdot e^x=0$$ метод половинного деления, метод касательных
    24 $$\sqrt{x+6.5}-e^x=0$$ метод хорд, метод простой итерации
    25 $$0.5^x+1-(x-2)^2=0$$ метод половинного деления, метод хорд
    Вернуться к учебному плану