Структура программы на языке c кратко. Типовая структура программы. Функции GETS, GETCH

Для начала рассмотрим случай функции двух переменных. Условным экстремумом функции $z=f(x,y)$ в точке $M_0(x_0;y_0)$ называется экстремум этой функции, достигнутый при условии, что переменные $x$ и $y$ в окрестности данной точки удовлетворяют уравнению связи $\varphi (x,y)=0$.

Название «условный» экстремум связано с тем, что на переменные наложено дополнительное условие $\varphi(x,y)=0$. Если из уравнения связи можно выразить одну переменную через другую, то задача определения условного экстремума сводится к задаче на обычный экстремум функции одной переменной. Например, если из уравнения связи следует $y=\psi(x)$, то подставив $y=\psi(x)$ в $z=f(x,y)$, получим функцию одной переменной $z=f\left(x,\psi(x)\right)$. В общем случае, однако, такой метод малопригоден, поэтому требуется введение нового алгоритма.

Метод множителей Лагранжа для функций двух переменных.

Метод множителей Лагранжа состоит в том, что для отыскания условного экстремума составляют функцию Лагранжа: $F(x,y)=f(x,y)+\lambda\varphi(x,y)$ (параметр $\lambda$ называют множителем Лагранжа). Необходимые условия экстремума задаются системой уравнений, из которой определяются стационарные точки:

$$ \left \{ \begin{aligned} & \frac{\partial F}{\partial x}=0;\\ & \frac{\partial F}{\partial y}=0;\\ & \varphi (x,y)=0. \end{aligned} \right. $$

Достаточным условием, из которого можно выяснить характер экстремума, служит знак $d^2 F=F_{xx}^{""}dx^2+2F_{xy}^{""}dxdy+F_{yy}^{""}dy^2$. Если в стационарной точке $d^2F > 0$, то функция $z=f(x,y)$ имеет в данной точке условный минимум, если же $d^2F < 0$, то условный максимум.

Есть и другой способ для определения характера экстремума. Из уравнения связи получаем: $\varphi_{x}^{"}dx+\varphi_{y}^{"}dy=0$, $dy=-\frac{\varphi_{x}^{"}}{\varphi_{y}^{"}}dx$, поэтому в любой стационарной точке имеем:

$$d^2 F=F_{xx}^{""}dx^2+2F_{xy}^{""}dxdy+F_{yy}^{""}dy^2=F_{xx}^{""}dx^2+2F_{xy}^{""}dx\left(-\frac{\varphi_{x}^{"}}{\varphi_{y}^{"}}dx\right)+F_{yy}^{""}\left(-\frac{\varphi_{x}^{"}}{\varphi_{y}^{"}}dx\right)^2=\\ =-\frac{dx^2}{\left(\varphi_{y}^{"} \right)^2}\cdot\left(-(\varphi_{y}^{"})^2 F_{xx}^{""}+2\varphi_{x}^{"}\varphi_{y}^{"}F_{xy}^{""}-(\varphi_{x}^{"})^2 F_{yy}^{""} \right)$$

Второй сомножитель (расположенный в скобке) можно представить в такой форме:

Красным цветом выделены элементы определителя $\left| \begin{array} {cc} F_{xx}^{""} & F_{xy}^{""} \\ F_{xy}^{""} & F_{yy}^{""} \end{array} \right|$, который является гессианом функции Лагранжа. Если $H > 0$, то $d^2F < 0$, что указывает на условный максимум. Аналогично, при $H < 0$ имеем $d^2F > 0$, т.е. имеем условный минимум функции $z=f(x,y)$.

Примечание относительно формы записи определителя $H$. показать\скрыть

$$ H=-\left|\begin{array} {ccc} 0 & \varphi_{x}^{"} & \varphi_{y}^{"}\\ \varphi_{x}^{"} & F_{xx}^{""} & F_{xy}^{""} \\ \varphi_{y}^{"} & F_{xy}^{""} & F_{yy}^{""} \end{array} \right| $$

В этой ситуации сформулированное выше правило изменится следующим образом: если $H > 0$, то функция имеет условный минимум, а при $H < 0$ получим условный максимум функции $z=f(x,y)$. При решении задач следует учитывать такие нюансы.

Алгоритм исследования функции двух переменных на условный экстремум

  1. Составить функцию Лагранжа $F(x,y)=f(x,y)+\lambda\varphi(x,y)$
  2. Решить систему $ \left \{ \begin{aligned} & \frac{\partial F}{\partial x}=0;\\ & \frac{\partial F}{\partial y}=0;\\ & \varphi (x,y)=0. \end{aligned} \right.$
  3. Определить характер экстремума в каждой из найденных в предыдущем пункте стационарных точек. Для этого применить любой из указанных способов:
    • Составить определитель $H$ и выяснить его знак
    • С учетом уравнения связи вычислить знак $d^2F$

Метод множителей Лагранжа для функций n переменных

Допустим, мы имеем функцию $n$ переменных $z=f(x_1,x_2,\ldots,x_n)$ и $m$ уравнений связи ($n > m$):

$$\varphi_1(x_1,x_2,\ldots,x_n)=0; \; \varphi_2(x_1,x_2,\ldots,x_n)=0,\ldots,\varphi_m(x_1,x_2,\ldots,x_n)=0.$$

Обозначив множители Лагранжа как $\lambda_1,\lambda_2,\ldots,\lambda_m$, составим функцию Лагранжа:

$$F(x_1,x_2,\ldots,x_n,\lambda_1,\lambda_2,\ldots,\lambda_m)=f+\lambda_1\varphi_1+\lambda_2\varphi_2+\ldots+\lambda_m\varphi_m$$

Необходимые условия наличия условного экстремума задаются системой уравнений, из которой находятся координаты стационарных точек и значения множителей Лагранжа:

$$\left\{\begin{aligned} & \frac{\partial F}{\partial x_i}=0; (i=\overline{1,n})\\ & \varphi_j=0; (j=\overline{1,m}) \end{aligned} \right.$$

Выяснить, условный минимум или условный максимум имеет функция в найденной точке, можно, как и ранее, посредством знака $d^2F$. Если в найденной точке $d^2F > 0$, то функция имеет условный минимум, если же $d^2F < 0$, - то условный максимум. Можно пойти иным путем, рассмотрев следующую матрицу:

Определитель матрицы $\left| \begin{array} {ccccc} \frac{\partial^2F}{\partial x_{1}^{2}} & \frac{\partial^2F}{\partial x_{1}\partial x_{2}} & \frac{\partial^2F}{\partial x_{1}\partial x_{3}} &\ldots & \frac{\partial^2F}{\partial x_{1}\partial x_{n}}\\ \frac{\partial^2F}{\partial x_{2}\partial x_1} & \frac{\partial^2F}{\partial x_{2}^{2}} & \frac{\partial^2F}{\partial x_{2}\partial x_{3}} &\ldots & \frac{\partial^2F}{\partial x_{2}\partial x_{n}}\\ \frac{\partial^2F}{\partial x_{3} \partial x_{1}} & \frac{\partial^2F}{\partial x_{3}\partial x_{2}} & \frac{\partial^2F}{\partial x_{3}^{2}} &\ldots & \frac{\partial^2F}{\partial x_{3}\partial x_{n}}\\ \ldots & \ldots & \ldots &\ldots & \ldots\\ \frac{\partial^2F}{\partial x_{n}\partial x_{1}} & \frac{\partial^2F}{\partial x_{n}\partial x_{2}} & \frac{\partial^2F}{\partial x_{n}\partial x_{3}} &\ldots & \frac{\partial^2F}{\partial x_{n}^{2}}\\ \end{array} \right|$, выделенной в матрице $L$ красным цветом, есть гессиан функции Лагранжа. Используем следующее правило:

  • Если знаки угловых миноров $H_{2m+1},\; H_{2m+2},\ldots,H_{m+n}$ матрицы $L$ совпадают с знаком $(-1)^m$, то исследуемая стационарная точка является точкой условного минимума функции $z=f(x_1,x_2,x_3,\ldots,x_n)$.
  • Если знаки угловых миноров $H_{2m+1},\; H_{2m+2},\ldots,H_{m+n}$ чередуются, причём знак минора $H_{2m+1}$ совпадает с знаком числа $(-1)^{m+1}$, то исследуемая стационарная точка является точкой условного максимума функции $z=f(x_1,x_2,x_3,\ldots,x_n)$.

Пример №1

Найти условный экстремум функции $z(x,y)=x+3y$ при условии $x^2+y^2=10$.

Геометрическая интерпретация данной задачи такова: требуется найти наибольшее и наименьшее значение аппликаты плоскости $z=x+3y$ для точек ее пересечения с цилиндром $x^2+y^2=10$.

Выразить одну переменную через другую из уравнения связи и подставить ее в функцию $z(x,y)=x+3y$ несколько затруднительно, поэтому будем использовать метод Лагранжа.

Обозначив $\varphi(x,y)=x^2+y^2-10$, составим функцию Лагранжа:

$$ F(x,y)=z(x,y)+\lambda \varphi(x,y)=x+3y+\lambda(x^2+y^2-10);\\ \frac{\partial F}{\partial x}=1+2\lambda x; \frac{\partial F}{\partial y}=3+2\lambda y. $$

Запишем систему уравнений для определения стационарных точек функции Лагранжа:

$$ \left \{ \begin{aligned} & 1+2\lambda x=0;\\ & 3+2\lambda y=0;\\ & x^2+y^2-10=0. \end{aligned} \right. $$

Если предположить $\lambda=0$, то первое уравнение станет таким: $1=0$. Полученное противоречие говорит о том, что $\lambda\neq 0$. При условии $\lambda\neq 0$ из первого и второго уравнений имеем: $x=-\frac{1}{2\lambda}$, $y=-\frac{3}{2\lambda}$. Подставляя полученные значения в третье уравнение, получим:

$$ \left(-\frac{1}{2\lambda} \right)^2+\left(-\frac{3}{2\lambda} \right)^2-10=0;\\ \frac{1}{4\lambda^2}+\frac{9}{4\lambda^2}=10; \lambda^2=\frac{1}{4}; \left[ \begin{aligned} & \lambda_1=-\frac{1}{2};\\ & \lambda_2=\frac{1}{2}. \end{aligned} \right.\\ \begin{aligned} & \lambda_1=-\frac{1}{2}; \; x_1=-\frac{1}{2\lambda_1}=1; \; y_1=-\frac{3}{2\lambda_1}=3;\\ & \lambda_2=\frac{1}{2}; \; x_2=-\frac{1}{2\lambda_2}=-1; \; y_2=-\frac{3}{2\lambda_2}=-3.\end{aligned} $$

Итак, система имеет два решения: $x_1=1;\; y_1=3;\; \lambda_1=-\frac{1}{2}$ и $x_2=-1;\; y_2=-3;\; \lambda_2=\frac{1}{2}$. Выясним характер экстремума в каждой стационарной точке: $M_1(1;3)$ и $M_2(-1;-3)$. Для этого вычислим определитель $H$ в каждой из точек.

$$ \varphi_{x}^{"}=2x;\; \varphi_{y}^{"}=2y;\; F_{xx}^{""}=2\lambda;\; F_{xy}^{""}=0;\; F_{yy}^{""}=2\lambda.\\ H=\left| \begin{array} {ccc} 0 & \varphi_{x}^{"} & \varphi_{y}^{"}\\ \varphi_{x}^{"} & F_{xx}^{""} & F_{xy}^{""} \\ \varphi_{y}^{"} & F_{xy}^{""} & F_{yy}^{""} \end{array} \right|= \left| \begin{array} {ccc} 0 & 2x & 2y\\ 2x & 2\lambda & 0 \\ 2y & 0 & 2\lambda \end{array} \right|= 8\cdot\left| \begin{array} {ccc} 0 & x & y\\ x & \lambda & 0 \\ y & 0 & \lambda \end{array} \right| $$

В точке $M_1(1;3)$ получим: $H=8\cdot\left| \begin{array} {ccc} 0 & x & y\\ x & \lambda & 0 \\ y & 0 & \lambda \end{array} \right|= 8\cdot\left| \begin{array} {ccc} 0 & 1 & 3\\ 1 & -1/2 & 0 \\ 3 & 0 & -1/2 \end{array} \right|=40 > 0$, поэтому в точке $M_1(1;3)$ функция $z(x,y)=x+3y$ имеет условный максимум, $z_{\max}=z(1;3)=10$.

Аналогично, в точке $M_2(-1;-3)$ найдем: $H=8\cdot\left| \begin{array} {ccc} 0 & x & y\\ x & \lambda & 0 \\ y & 0 & \lambda \end{array} \right|= 8\cdot\left| \begin{array} {ccc} 0 & -1 & -3\\ -1 & 1/2 & 0 \\ -3 & 0 & 1/2 \end{array} \right|=-40$. Так как $H < 0$, то в точке $M_2(-1;-3)$ имеем условный минимум функции $z(x,y)=x+3y$, а именно: $z_{\min}=z(-1;-3)=-10$.

Отмечу, что вместо вычисления значения определителя $H$ в каждой точке, гораздо удобнее раскрыть его в общем виде. Дабы не загромождать текст подробностями, этот способ скрою под примечание.

Запись определителя $H$ в общем виде. показать\скрыть

$$ H=8\cdot\left|\begin{array}{ccc}0&x&y\\x&\lambda&0\\y&0&\lambda\end{array}\right| =8\cdot\left(-\lambda{y^2}-\lambda{x^2}\right) =-8\lambda\cdot\left(y^2+x^2\right). $$

В принципе, уже очевидно, какой знак имеет $H$. Так как ни одна из точек $M_1$ или $M_2$ не совпадает с началом координат, то $y^2+x^2>0$. Следовательно, знак $H$ противоположен знаку $\lambda$. Можно и довести вычисления до конца:

$$ \begin{aligned} &H(M_1)=-8\cdot\left(-\frac{1}{2}\right)\cdot\left(3^2+1^2\right)=40;\\ &H(M_2)=-8\cdot\frac{1}{2}\cdot\left((-3)^2+(-1)^2\right)=-40. \end{aligned} $$

Вопрос о характере экстремума в стационарных точках $M_1(1;3)$ и $M_2(-1;-3)$ можно решить и без использования определителя $H$. Найдем знак $d^2F$ в каждой стационарной точке:

$$ d^2 F=F_{xx}^{""}dx^2+2F_{xy}^{""}dxdy+F_{yy}^{""}dy^2=2\lambda \left(dx^2+dy^2\right) $$

Отмечу, что запись $dx^2$ означает именно $dx$, возведённый в вторую степень, т.е. $\left(dx \right)^2$. Отсюда имеем: $dx^2+dy^2>0$, посему при $\lambda_1=-\frac{1}{2}$ получим $d^2F < 0$. Следовательно, функция имеет в точке $M_1(1;3)$ условный максимум. Аналогично, в точке $M_2(-1;-3)$ получим условный минимум функции $z(x,y)=x+3y$. Отметим, что для определения знака $d^2F$ не пришлось учитывать связь между $dx$ и $dy$, ибо знак $d^2F$ очевиден без дополнительных преобразований. В следующем примере для определения знака $d^2F$ уже будет необходимо учесть связь между $dx$ и $dy$.

Ответ : в точке $(-1;-3)$ функция имеет условный минимум, $z_{\min}=-10$. В точке $(1;3)$ функция имеет условный максимум, $z_{\max}=10$

Пример №2

Найти условный экстремум функции $z(x,y)=3y^3+4x^2-xy$ при условии $x+y=0$.

Первый способ (метод множителей Лагранжа)

Обозначив $\varphi(x,y)=x+y$ составим функцию Лагранжа: $F(x,y)=z(x,y)+\lambda \varphi(x,y)=3y^3+4x^2-xy+\lambda(x+y)$.

$$ \frac{\partial F}{\partial x}=8x-y+\lambda; \; \frac{\partial F}{\partial y}=9y^2-x+\lambda.\\ \left \{ \begin{aligned} & 8x-y+\lambda=0;\\ & 9y^2-x+\lambda=0; \\ & x+y=0. \end{aligned} \right. $$

Решив систему, получим: $x_1=0$, $y_1=0$, $\lambda_1=0$ и $x_2=\frac{10}{9}$, $y_2=-\frac{10}{9}$, $\lambda_2=-10$. Имеем две стационарные точки: $M_1(0;0)$ и $M_2 \left(\frac{10}{9};-\frac{10}{9} \right)$. Выясним характер экстремума в каждой стационарной точке с использованием определителя $H$.

$$ H=\left| \begin{array} {ccc} 0 & \varphi_{x}^{"} & \varphi_{y}^{"}\\ \varphi_{x}^{"} & F_{xx}^{""} & F_{xy}^{""} \\ \varphi_{y}^{"} & F_{xy}^{""} & F_{yy}^{""} \end{array} \right|= \left| \begin{array} {ccc} 0 & 1 & 1\\ 1 & 8 & -1 \\ 1 & -1 & 18y \end{array} \right|=-10-18y $$

В точке $M_1(0;0)$ $H=-10-18\cdot 0=-10 < 0$, поэтому $M_1(0;0)$ есть точка условного минимума функции $z(x,y)=3y^3+4x^2-xy$, $z_{\min}=0$. В точке $M_2\left(\frac{10}{9};-\frac{10}{9}\right)$ $H=10 > 0$, посему в данной точке функция имеет условный максимум, $z_{\max}=\frac{500}{243}$.

Исследуем характер экстремума в каждой из точек иным методом, основываясь на знаке $d^2F$:

$$ d^2 F=F_{xx}^{""}dx^2+2F_{xy}^{""}dxdy+F_{yy}^{""}dy^2=8dx^2-2dxdy+18ydy^2 $$

Из уравнения связи $x+y=0$ имеем: $d(x+y)=0$, $dx+dy=0$, $dy=-dx$.

$$ d^2 F=8dx^2-2dxdy+18ydy^2=8dx^2-2dx(-dx)+18y(-dx)^2=(10+18y)dx^2 $$

Так как $ d^2F \Bigr|_{M_1}=10 dx^2 > 0$, то $M_1(0;0)$ является точкой условного минимума функции $z(x,y)=3y^3+4x^2-xy$. Аналогично, $d^2F \Bigr|_{M_2}=-10 dx^2 < 0$, т.е. $M_2\left(\frac{10}{9}; -\frac{10}{9} \right)$ - точка условного максимума.

Второй способ

Из уравнения связи $x+y=0$ получим: $y=-x$. Подставив $y=-x$ в функцию $z(x,y)=3y^3+4x^2-xy$, получим некоторую функцию переменной $x$. Обозначим эту функцию как $u(x)$:

$$ u(x)=z(x,-x)=3\cdot(-x)^3+4x^2-x\cdot(-x)=-3x^3+5x^2. $$

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

$$ u_{x}^{"}=-9x^2+10x;\\ -9x^2+10x=0; \; x\cdot(-9x+10)=0;\\ x_1=0; \; y_1=-x_1=0;\\ x_2=\frac{10}{9}; \; y_2=-x_2=-\frac{10}{9}. $$

Получили точки $M_1(0;0)$ и $M_2\left(\frac{10}{9}; -\frac{10}{9}\right)$. Дальнейшее исследование известно из курса дифференциального исчисления функций одной переменой. Исследуя знак $u_{xx}^{""}$ в каждой стационарной точке или проверяя смену знака $u_{x}^{"}$ в найденных точках, получим те же выводы, что и при решении первым способом. Например, проверим знак $u_{xx}^{""}$:

$$u_{xx}^{""}=-18x+10;\\ u_{xx}^{""}(M_1)=10;\;u_{xx}^{""}(M_2)=-10.$$

Так как $u_{xx}^{""}(M_1)>0$, то $M_1$ - точка минимума функции $u(x)$, при этом $u_{\min}=u(0)=0$. Так как $u_{xx}^{""}(M_2)<0$, то $M_2$ - точка максимума функции $u(x)$, причём $u_{\max}=u\left(\frac{10}{9}\right)=\frac{500}{243}$.

Значения функции $u(x)$ при заданном условии связи совпадают с значениями функции $z(x,y)$, т.е. найденные экстремумы функции $u(x)$ и есть искомые условные экстремумы функции $z(x,y)$.

Ответ : в точке $(0;0)$ функция имеет условный минимум, $z_{\min}=0$. В точке $\left(\frac{10}{9}; -\frac{10}{9} \right)$ функция имеет условный максимум, $z_{\max}=\frac{500}{243}$.

Рассмотрим еще один пример, в котором характер экстремума выясним посредством определения знака $d^2F$.

Пример №3

Найти наибольшее и наименьшее значения функции $z=5xy-4$, если переменные $x$ и $y$ положительны и удовлетворяют уравнению связи $\frac{x^2}{8}+\frac{y^2}{2}-1=0$.

Составим функцию Лагранжа: $F=5xy-4+\lambda \left(\frac{x^2}{8}+\frac{y^2}{2}-1 \right)$. Найдем стационарные точки функции Лагранжа:

$$ F_{x}^{"}=5y+\frac{\lambda x}{4}; \; F_{y}^{"}=5x+\lambda y.\\ \left \{ \begin{aligned} & 5y+\frac{\lambda x}{4}=0;\\ & 5x+\lambda y=0;\\ & \frac{x^2}{8}+\frac{y^2}{2}-1=0;\\ & x > 0; \; y > 0. \end{aligned} \right. $$

Все дальнейшие преобразования осуществляются с учетом $x > 0; \; y > 0$ (это оговорено в условии задачи). Из второго уравнения выразим $\lambda=-\frac{5x}{y}$ и подставим найденное значение в первое уравнение: $5y-\frac{5x}{y}\cdot \frac{x}{4}=0$, $4y^2-x^2=0$, $x=2y$. Подставляя $x=2y$ в третье уравнение, получим: $\frac{4y^2}{8}+\frac{y^2}{2}-1=0$, $y^2=1$, $y=1$.

Так как $y=1$, то $x=2$, $\lambda=-10$. Характер экстремума в точке $(2;1)$ определим, исходя из знака $d^2F$.

$$ F_{xx}^{""}=\frac{\lambda}{4}; \; F_{xy}^{""}=5; \; F_{yy}^{""}=\lambda. $$

Так как $\frac{x^2}{8}+\frac{y^2}{2}-1=0$, то:

$$ d\left(\frac{x^2}{8}+\frac{y^2}{2}-1\right)=0; \; d\left(\frac{x^2}{8} \right)+d\left(\frac{y^2}{2} \right)=0; \; \frac{x}{4}dx+ydy=0; \; dy=-\frac{xdx}{4y}. $$

В принципе, здесь можно сразу подставить координаты стационарной точки $x=2$, $y=1$ и параметра $\lambda=-10$, получив при этом:

$$ F_{xx}^{""}=\frac{-5}{2}; \; F_{xy}^{""}=-10; \; dy=-\frac{dx}{2}.\\ d^2 F=F_{xx}^{""}dx^2+2F_{xy}^{""}dxdy+F_{yy}^{""}dy^2=-\frac{5}{2}dx^2+10dx\cdot \left(-\frac{dx}{2} \right)-10\cdot \left(-\frac{dx}{2} \right)^2=\\ =-\frac{5}{2}dx^2-5dx^2-\frac{5}{2}dx^2=-10dx^2. $$

Однако в других задачах на условный экстремум стационарных точек может быть несколько. В таких случаях лучше $d^2F$ представить в общем виде, а потом подставлять в полученное выражение координаты каждой из найденных стационарных точек:

$$ d^2 F=F_{xx}^{""}dx^2+2F_{xy}^{""}dxdy+F_{yy}^{""}dy^2=\frac{\lambda}{4}dx^2+10\cdot dx\cdot \frac{-xdx}{4y} +\lambda\cdot \left(-\frac{xdx}{4y} \right)^2=\\ =\frac{\lambda}{4}dx^2-\frac{5x}{2y}dx^2+\lambda \cdot \frac{x^2dx^2}{16y^2}=\left(\frac{\lambda}{4}-\frac{5x}{2y}+\frac{\lambda \cdot x^2}{16y^2} \right)\cdot dx^2 $$

Подставляя $x=2$, $y=1$, $\lambda=-10$, получим:

$$ d^2 F=\left(\frac{-10}{4}-\frac{10}{2}-\frac{10 \cdot 4}{16} \right)\cdot dx^2=-10dx^2. $$

Так как $d^2F=-10\cdot dx^2 < 0$, то точка $(2;1)$ есть точкой условного максимума функции $z=5xy-4$, причём $z_{\max}=10-4=6$.

Ответ : в точке $(2;1)$ функция имеет условный максимум, $z_{\max}=6$.

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

Определение1 : Говорят, что функция имеет в точке локальный максимум, если существует такая окрестность точки, для которой для всякой точки M с координатами (x, y) выполняется неравенство: . При этом, т. е. приращение функции < 0.

Определение2 : Говорят, что функция имеет в точке локальный минимум, если существует такая окрестность точки, для которой для всякой точки M с координатами (x, y) выполняется неравенство: . При этом, т. е. приращение функции > 0.

Определение 3 : Точки локальных минимума и максимума называются точками экстремума .

Условные Экстремумы

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

Пусть заданы функция и линия L на плоскости 0xy . Задача состоит в том, чтобы на линии L найти такую точку P(x, y), в которой значение функции является наибольшим или наименьшим по сравнению со значениями этой функции в точках линии L , находящихся вблизи точки P . Такие точки P называются точками условного экстремума функции на линии L . В отличие от обычной точки экстремума значение функции в точке условного экстремума сравнивается со значениями функции не во всех точках некоторой ее окрестности, а только в тех, которые лежат на линии L .

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

Эта функция имеет максимум в начале координат; ему соответствует вершина M полусферы. Если линия L есть прямая, проходящая через точки А и В (ее уравнение x+y-1=0 ), то геометрически ясно, что для точек этой линии наибольшее значение функции достигается в точке, лежащей посередине между точками А и В. Это и есть точка условного экстремума (максимума) функции на данной линии; ей соответствует точка M 1 на полусфере, и из рисунка видно, что ни о каком обычном экстремуме здесь не может быть речи.

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

Приступим теперь к практическому отысканию точек условного экстремума функции Z= f(x, y) при условии, что переменные x и y связаны уравнением (x, y) = 0. Это соотношение будем называть уравнение связи. Если из уравнения связи y можно выразить явно через х: y=(x), мы получим функцию одной переменной Z= f(x, (x)) = Ф(х).

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

Так, в вышеприведенном примере из уравнения связи x+y-1=0 имеем y=1-х. Отсюда

Легко проверить, что z достигает максимума при х = 0,5; но тогда из уравнения связи y=0,5, и мы получаем как раз точку P, найденную из геометрических соображений.

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

Если уравнение связи имеет более сложный вид и нам не удается ни явно выразить одну переменную через другую, ни заменить его параметрическими уравнениями, то задача отыскания условного экстремума становится более трудной. Будем по-прежнему считать, что в выражении функции z= f(x, y) переменная (x, y) = 0. Полная производная от функции z= f(x, y) равна:

Где производная y`, найдена по правилу дифференцирования неявной функции. В точках условного экстремума найденная полная производная должна ровняться нулю; это дает одно уравнение, связывающее х и у. Так как они должны удовлетворять еще и уравнению связи, то мы получаем систему двух уравнений с двумя неизвестными

Преобразуем эту систему к гораздо более удобной, записав первое уравнение в виде пропорции и введя новую вспомогательную неизвестную:

(знак минус перед поставлен для удобства). От этих равенств легко перейти к следующей системе:

f` x =(x,y)+` x (x,y)=0, f` y (x,y)+` y (x,y)=0 (*),

которая вместе с уравнением связи (x, y) = 0 образует систему трех уравнений с неизвестными х, у и.

Эти уравнения (*) легче всего запомнить при помощи следующего правила: для того, чтобы найти точки, которые могут быть точками условного экстремума функции

Z= f(x, y) при уравнении связи (x, y) = 0, нужно образовать вспомогательную функцию

Ф(х,у)=f(x,y)+(x,y)

Где -некоторая постоянная, и составить уравнения для отыскания точек экстремума этой функции.

Указанная система уравнений доставляет, как правило, только необходимые условия, т.е. не всякая пара значений х и у, удовлетворяющая этой системе, обязательно является точкой условного экстремума. Достаточные условия для точек условного экстремума я приводить не стану; очень часто конкретное содержание задачи само подсказывает, чем является найденная точка. Описанный прием решения задач на условный экстремум называется методом множителей Лагранжа.

Из чего состоит программа

Для начала стоит понять, что программу нельзя читать и писать как книгу: от корки до корки, сверху вниз, строку за строкой. Любая программа состоит из отдельных блоков. Начало блока кода в C/C++ обозначается левой фигурной скобкой { , его конец - правой фигурной скобкой } .

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

В данном случае у нас 2 функции с именами setup и loop . Их присутствие обязательно в любой программе на C++ для Arduino. Они могут ничего и не делать, как в нашем случае, но должны быть написаны. Иначе на стадии компиляции вы получите ошибку.

Классика жанра: мигающий светодиод

Давайте теперь дополним нашу программу так, чтобы происходило хоть что-то. На Arduino, к 13-му пину подключён светодиод. Им можно управлять, чем мы и займёмся.

void setup() { pinMode(13 , OUTPUT) ; } void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; digitalWrite(13 , LOW) ; delay(900 ) ; }

Скомпилируйте, загрузите программу. Вы увидите, что каждую секунду светодиод на плате помигивает. Разберёмся почему этот код приводит к ежесекундному миганию.

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

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

    Как только Arduino включается, перепрошивается или нажимается кнопка RESET , «нечто» вызывает функцию setup . То есть заставляет исполняться выражения в ней.

    Как только работа setup завершается, сразу же «нечто» вызывает функцию loop .

    Как только работа loop завершается, сразу же «нечто» вызывает функцию loop ещё раз и так до бесконечности.

Если пронумеровать выражения по порядку, как они исполняются, получится:

void setup() { pinMode(13 , OUTPUT) ; ❶ } void loop() { digitalWrite(13 , HIGH) ; ❷ ❻ ❿ delay(100 ) ; ❸ ❼ … digitalWrite(13 , LOW) ; ❹ ❽ delay(900 ) ; ❺ ❾ }

Ещё раз напомним, что не стоит пытаться воспринимать всю программу, читая сверху вниз. Сверху вниз читается только содержимое блоков. Мы вообще можем поменять порядок объявлений setup и loop .

void loop() { digitalWrite(13 , HIGH) ; ❷ ❻ ❿ delay(100 ) ; ❸ ❼ … digitalWrite(13 , LOW) ; ❹ ❽ delay(900 ) ; ❺ ❾ } void setup() { pinMode(13 , OUTPUT) ; ❶ }

Результат от этого не изменится ни на йоту: после компиляции вы получите абсолютно эквивалентный бинарный файл.

Что делают выражения

Теперь давайте попробуем понять почему написанная программа приводит в итоге к миганию светодиода.

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

Это делается выражением в функции setup:

PinMode(13 , OUTPUT) ;

Выражения бывают разными: арифметическими, декларациями, определениями, условными и т.д. В данном случае мы в выражении осуществляем вызов функции . Помните? У нас есть свои функции setup и loop , которые вызываются чем-то, что мы назвали «нечто». Так вот теперь мы вызываем функции, которые уже написаны где-то.

Конкретно в нашем setup мы вызываем функцию с именем pinMode . Она устанавливает заданный по номеру пин в заданный режим: вход или выход. О каком пине и о каком режиме идёт речь указывается нами в круглых скобках, через запятую, сразу после имени функции. В нашем случае мы хотим, чтобы 13-й пин работал как выход. OUTPUT означает выход, INPUT - вход.

Уточняющие значения, такие как 13 и OUTPUT называются аргументами функции . Совершенно не обязательно, что у всех функций должно быть по 2 аргумента. Сколько у функции аргументов зависит от сути функции, от того как её написал автор. Могут быть функции с одним аргументом, тремя, двадцатью; функции могут быть без аргументов вовсе. Тогда для их вызова круглые скобка открывается и тут же закрывается:

NoInterrupts() ;

На самом деле, вы могли заметить, наши функции setup и loop также не принимают никакие аргументы. И загадочное «нечто» точно так же вызывает их с пустыми скобками в нужный момент.

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

Перейдём к функции loop:

void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; digitalWrite(13 , LOW) ; delay(900 ) ; }

Она, как говорилось, вызывается сразу после setup . И вызывается снова и снова как только сама заканчивается. Функция loop называется основным циклом программы и идеологически предназначена для выполнения полезной работы. В нашем случае полезная работа - мигание светодиодом.

Пройдёмся по выражениям по порядку. Итак, первое выражение - это вызов встроенной функции digitalWrite . Она предназначена для подачи на заданный пин логического нуля (LOW , 0 вольт) или логической единицы (HIGH , 5 вольт) В функцию digitalWrite передаётся 2 аргумента: номер пина и логическое значение. В итоге, первым делом мы зажигаем светодиод на 13-м пине, подавая на него 5 вольт.

Как только это сделано процессор моментально приступает к следующему выражению. У нас это вызов функции delay . Функция delay - это, опять же, встроенная функция, которая заставляет процессор уснуть на определённое время. Она принимает всего один аргумент: время в миллисекундах, которое следует спать. В нашем случае это 100 мс.

Пока мы спим всё остаётся как есть, т.е. светодиод продолжает гореть. Как только 100 мс истекают, процессор просыпается и тут же переходит к следующему выражению. В нашем примере это снова вызов знакомой нам встроенной функции digitalWrite . Правда на этот раз вторым аргументом мы передаём значение LOW . То есть устанавливаем на 13-м пине логический ноль, то есть подаём 0 вольт, то есть гасим светодиод.

После того, как светодиод погашен мы приступаем к следующему выражению. И снова это вызов функции delay . На этот раз мы засыпаем на 900 мс.

Как только сон окончен, функция loop завершается. По факту завершения «нечто» тут же вызывает её ещё раз и всё происходит снова: светодиод поджигается, горит, гаснет, ждёт и т.д.

Если перевести написанное на русский, получится следующий алгоритм:

    Поджигаем светодиод

    Спим 100 миллисекунд

    Гасим светодиод

    Спим 900 миллисекунд

    Переходим к пункту 1

Таким образом мы получили Arduino с маячком, мигающим каждые 100 + 900 мс = 1000 мс = 1 сек.

Что можно изменить

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

Вы можете подключить внешний светодиод или другое устройство, которым нужно «мигать» на другой пин. Например, на 5-й. Как в этом случае должна измениться программа? Мы должны всюду, где обращались к 13-му пину заменить номер на 5-й:

Компилируйте, загружайте, проверяйте.

Что нужно сделать, чтобы светодиод мигал 2 раза в секунду? Уменьшить время сна так, чтобы в сумме получилось 500 мс:

void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(450 ) ; }

Как сделать так, чтобы светодиод при каждом «подмигивании» мерцал дважды? Нужно поджигать его дважды с небольшой паузой между включениями:

void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(50 ) ; digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(350 ) ; }

Как сделать так, чтобы в устройстве были 2 светодиода, которые мигали бы каждую секунду поочерёдно? Нужно общаться с двумя пинами и работать в loop то с одним, то с другим:

void setup() { pinMode(5 , OUTPUT) ; pinMode(6 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; digitalWrite(6 , HIGH) ; delay(100 ) ; digitalWrite(6 , LOW) ; delay(900 ) ; }

Как сделать так, чтобы в устройстве были 2 светодиода, которые переключались бы на манер железнодорожного светофора: горел бы то один то другой? Нужно просто не выключать горящий светодиод тут же, а дожидаться момента переключения:

void setup() { pinMode(5 , OUTPUT) ; pinMode(6 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; digitalWrite(6 , LOW) ; delay(1000 ) ; digitalWrite(5 , LOW) ; digitalWrite(6 , HIGH) ; delay(1000 ) ; }

Можете проверить другие идеи самостоятельно. Как видите, всё просто!

О пустом месте и красивом коде

В языке C++ пробелы, переносы строк, символы табуляции не имеют большого значения для компилятора. Там где стоит пробел, может быть перенос строки и наоборот. На самом деле 10 пробелов подряд, 2 переноса строки и ещё 5 пробелов - это всё эквивалент одного пробела.

Пустое пространство - это инструмент программиста, с помощью которого можно или сделать программу понятной и наглядной, или изуродовать до неузнаваемости. Например, вспомним программу для мигания светодиодом:

void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

Мы можем изменить её так:

void setup( ) { pinMode(5 , OUTPUT) ; } void loop () { digitalWrite(5 ,HIGH) ; delay(100 ) ; digitalWrite(5 ,LOW) ; delay(900 ) ; }

Всё, что мы сделали - немного «поработали» с пустым пространством. Теперь можно наглядно видеть разницу между стройным кодом и нечитаемым.

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

1. Всегда, при начале нового блока между { и } увеличивайте отступ. Обычно используют 2 или 4 пробела. Выберите одно из значений и придерживайтесь его всюду.

Плохо:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

Хорошо:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

2. Как и в естественном языке: ставьте пробел после запятых и не ставьте до.

Плохо:

DigitalWrite(5 ,HIGH) ; digitalWrite(5 , HIGH) ; digitalWrite(5 ,HIGH) ;

Хорошо:

DigitalWrite(5 , HIGH) ;

3. Размещайте символ начала блока { на новой строке на текущем уровне отступа или в конце предыдущей. А символ конца блока } на отдельной строке на текущем уровне отступа:

Плохо:

void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; }

Хорошо:

void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; }

4. Используйте пустые строки для разделения смысловых блоков:

Хорошо:

Ещё лучше:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; digitalWrite(6 , HIGH) ; delay(100 ) ; digitalWrite(6 , LOW) ; delay(900 ) ; }

О точках с запятыми

Вы могли заинтересоваться: зачем в конце каждого выражения ставится точка с запятой? Таковы правила C++. Подобные правила называются синтаксисом языка . По символу; компилятор понимает где заканчивается выражение.

Как уже говорилось, переносы строк для него - пустой звук, поэтому ориентируется он на этот знак препинания. Это позволяет записывать сразу несколько выражений в одной строке:

void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }

Программа корректна и эквивалентна тому, что мы уже видели. Однако писать так - это дурной тон. Код гораздо сложнее читается. Поэтому если у вас нет 100% веских причин писать в одной строке несколько выражений, не делайте этого.

О комментариях

Одно из правил качественного программирования: «пишите код так, чтобы он был настолько понятным, что не нуждался бы в пояснениях». Это возможно, но не всегда. Для того, чтобы пояснить какие-то не очевидные моменты в коде его читателям: вашим коллегам или вам самому через месяц, существуют так называемые комментарии.

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

/* Функция setup вызывается самой первой, при подаче питания на Arduino А это многострочный комментарий */ void setup() { // устанавливаем 13-й пин в режим вывода pinMode(13 , OUTPUT) ; } void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; // спим 100 мс digitalWrite(13 , LOW) ; delay(900 ) ; }

Как видите, между символами /* и */ можно писать сколько угодно строк комментариев. А после последовательности / / комментарием считается всё, что следует до конца строки.

Итак, надеемся самые основные принципы составления написания программ стали понятны. Полученные знания позволяют программно управлять подачей питания на пины Arduino по определённым временны́м схемам. Это не так уж много, но всё же достаточно для первых экспериментов.

Рис.1 Структура программы на языке Си.

Внутренняя структура программы

Исполняемая программа на Си состоит из 4 частей: область команд, область статических данных, область динамических данных, область стека. см. Рис.2.

1. Область команд содержит машинные команды; инструкции, которые должен выполнить микропроцессор.

2. Область статических данных для хранения переменных, с которыми работает программа;

3. Область динамических данных для размещения дополнительных данных, которые появляются в процессе работы программы (например, временных переменных).

4. Стек используется для временного хранения данных и адресов возврата из функций.


тело функции /*тело функции*/

printf("Hello World!");

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



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

3-я строка – начало тела функции. {} определяют тело функции (в Паскале - это begin и end)

4-я строка – комментарий, он не компилируется, а только поясняет что делается.

5-я строка – библиотечная функция – печатать на экране, выражение в скобках на этой строке – параметр функции, он всегда берётся в кавычки.

; - это признак оператора Си, это часть оператора, а не разделитель операторов, как в Паскале.

Советы, как сделать программу читаемой:

1) Выбирать осмысленные имена

2) Использовать комментарии

3) Использовать пустые строки для того, чтобы отделить одну часть функции от другой

4) Помещать каждый оператор в другой строке.

БАЗОВЫЕ ЭЛЕМЕНТЫ ЯЗЫКА СИ

Рассмотрим обязательные элементы, с помощью которых должна оформляться программа на Си:

1. Комментарии – используются для документирования программы. Любая программа должна содержать комментарии: какой алгоритм применяется, что делает программа…

Ø 1 способ : /* Текст */ - в любом месте программы.

Как только компилятор встречает /**/, он их пропускает. Компилятор игнорирует /* */, так как он не в состоянии интерпретировать язык, отличающийся от языка Си. То есть, если вы хотите исключить из компиляции какую-то строку, то заключите её в /**/.

Ø 2 способ : если комментарий большой, то используем такой тип

/* Строка 1 - для комментария любой длины

строка 3*/

Ø 3 способ : // - текст до конца строки.

2. Идентификатор - это имя, которое присваивается какому-либо объекту (переменной). Используются строчные и прописные буквы, цифры и знак подчёркивания. Строчные и прописные буквы различаются. (В Бейсике не различаются). Если назвать переменную name, Name или NAME, то это будут разные переменные.

Начинаются идентификаторы с буквы или знака подчеркивания. Например, _name. Но не рекомендуется начинать с _, так как этот знак используется для глобальных имен сомого языка Си.

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

b – байт; ch – однобайтовый символ;

w – слово; f – флаг;

l – длинное слово; fn – функция;

u – беззнаковое; p – указатель;

с – счетчик; d – разность двух пре-х

cz – строка; и т.д.

3. Служебные слова – это слова, с которыми в языке жестко сопоставлены определённые смысловые значения и которые не могут быть использованы для других целей. Это имена операторов, библиотечных функций, команды препроцессора и так далее. Этим слова нельзя использовать для создания имен своих функций, переменных…

ДАННЫЕ В ПРОГРАММЕ НА СИ

Каждая программа оперирует с данными . Они присутствуют в программе в виде переменных и констант.

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

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

Константы

Константы - это фиксированные значения. Значение, будучи установлено, больше не меняется. Константы бывают различных типов. Типы отличаются по принципу размещения в памяти ЭВМ, а для человека по виду записи. В Си существует 7 ключевых слов, используемых для указания на различные типы данных: int, long, short, unsigned, char, float, double.

Типы констант :

a) Целые и длинные целые . Записываются в десятичной, восьмеричной и шестнадцатеричной системе счисления. Они могут быть знаковые и беззнаковые.

Десятичная система: целые константы занимают 16 бит памяти, и принимают диапазон значений: -32768 до +32767 (2 15) . Если константа беззнаковая, то диапазон удваивается: 0 до 65535 (за счет того, что 15-й разряд – знаковый используется под число). Для обозначения беззнакового числа используют суффикс u (unsigned), например 123u.

Если число больше 40000, то компилятор автоматически преобразует его в отрицательное число, поэтому суффикс u обязателен:40000u. В примере 123u компилятору все равно – есть суффикс или его нет, так как это число входит в диапазон 32767.

Длинное целое занимает 32 бита , диапазон значений

± 2147483648 (знаковое длинное – long). Если вы поставили суффикс l , то, несмотря на число, будет занято 32 бита. Например: -5326l

0 – 4294967295 беззнаковое длинное - (unsigned long). Диапазон увеличивается за счет 31-го бита. Используются суффиксы ul , например, 32659ul.

Восьмеричная система :

Если число начинается с цифры 0, оно интерпретируется как восьмиричное число

16 битов 0 ¸ 077777

0100000 ¸ 0177777u

32 бита 0200000 ¸ 01777777777l

020000000000 ¸ 037777777777ul

Шестнадцатеричная система :

Если число начинается с символа 0х, то оно интерпретируется как шестнадцатиричное

16 битов 0x0000 ¸ 0x7FFF

0x8000 ¸ 0xEFFFu

32 бита 0x10000 ¸ 0x7FFFFFFFl

0x80000000 ¸ 0xFFFFFFFFul

b) Вещественные константы . Это числа с плавающей точкой. Значение имеет дробную часть. По умолчанию все вещественные константы имеют тип двойной точности double . Занимают в памяти 8 байт (даже если 0,0). Диапазон значений ±1*10 ± 307 , можно записать и в научной форме, например: 0,5е+15 или

1,2е-3=1,2*10 -8 =0,0012.

Принудительно можно задать формат одинарной точности float . Число будет занимать 4 байта , используется суффикс f (5.7 f). Соответсвенно диапазон сужается ±1*10 ± 37

А также расширенной точности long double – 10 байт . (3.14L)

Знак + можно не писать. Разрешается опускать либо десятичную точку, либо экспоненциальную часть, но не одновременно (.2; 4е16). Можно не писать дробную либо целую часть, но не одновременно (100.; .8е-5)

c) Символьные константы. Это набор символов, используемых в ЭВМ.

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

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

Символ "А" "a" " " "\n"

Его код 65 97 32 10

Как целый тип данных "A"=0101 8 , 01000001 2 , 41 16 , 65 10 . Коды запоминать не надо.

Управляющие коды начинаются с символа \ и тоже заключаются в апострофы. Наиболее распространенные управляющие коды:

\n – переход на новую строку

\t – табуляция (сдвиг курсора на некоторое фиксированное значение)

\b – шаг назад (сдвиг на одну позицию назад)

\r – возврат каретки (возврат к началу строки)

\f – подача бланка (протяжка бумаги на 1 страницу)

\’ - апостроф

\” - кавычки

Последние три знака могут выступать символьными константами, а также применяться в функции printf() , поэтому применение их в качестве символов может привести к ошибке. Например, если мы хотим вывести строку «Символ \ называется слеш», то оператор должен выглядеть так:

рrintf(«Символ \\ называется слеш»);

a) Строковые константы - содержат последовательность из 1 и более символов, заключённых в " ". Расходуется по 1 байту на любой символ + 1байт на так называемый ноль-символ - признак конца строки. Ноль-символ – не цифра ноль, он означает, что количество символов в строке (N) должно быть на 1 байт больше (N+1), чтобы обозначать конец строки (компилятор его прибавляет сам автоматически). Например: «строка текста» занимает (13+1) байт;

«Мир» -

Пожалуйста, приостановите работу AdBlock на этом сайте.

Я надеюсь вы уже установили себе на компьютер какую-нибудь IDE и научились в ней компилировать программы. Если нет, то

Все программы, написанные на языке Си, имеют общую структуру. О которой мы и поговорим в этом уроке. В этом нам поможет наша первая программа, написанная на предыдущем шаге.

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

Рис.1 Карта "Структура программ на языке Си." Начальный уровень.

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

Сейчас внимание. Не пугайтесь! Ниже написан исходный код трёх простеньких программ. Ваша задача внимательно на них посмотреть и попытаться найти в их коде какую-то закономерность (нечто общее, что есть в каждой программе).

Листинг 1. Программа 1. Печатает «Hello, World!»

#include

Листинг 2. Программа 2

Int main(void) { int a, b, c; a = 5; b = 10; c = a+b; return 0; }

Листинг 3. Программа 3

#include int main(void) { FILE *fp; fp = fopen("input.txt", "w"); fprintf(fp, "This is Sparta!"); fclose(fp); return 0; }

Не торопитесь смотреть продолжение урока и правильный ответ на эту задачу. Для начала попробуйте ответить самостоятельно. После этого нажмите кнопку "Смотреть продолжение!"

Итак, ответ: Во всех программах выше присутствует следующая конструкция:

Листинг 4. Главная функция любой программы на языке Си - функция main.

Int main(void) { return 0; }

Что же это за конструкция. Это объявление функции main. Такая функция обязательно есть в каждой программе, которая написана на языке Си.Большая программа или маленькая, компьютерная игра или программа "Hello, World!", написана вами или Биллом Гейтсом -- если программа написана на языке Си -- в ней есть функция main. Это так сказать главная функция нашей программы. Когда мы запускаем программу, то можно думать, что запускаем функцию main этой программы.

Остановимся на секундочку. Мы, кажется, уже кое-что выяснили о структуре программ на языке Си. Любая программа на языке Си должна содержать функцию main. Отобразим этот факт на нашей карте знаний "Структура программ на языке Си."

Рис.2 Карта "Структура программ на языке Си." Функция main.

Теперь карта не напрягает нас своей зияющей пустотой. Продолжим наши исследования.

Давайте я расскажу немного о функции main и о функциях вообще.

Перед именем функции написано int, это сокращение от слова integer, которое переводится с английского, как "целое". Подобная запись означает, что когда функция main завершит свою работу, она должна вернуть вызывающей программе (в нашем случае это операционная система) какое-нибудь целое число. Обычно, для функции main это число ноль, которое оповещает операционную систему: "Мол, всё хорошо. Происшествий не случилось."

Случалось ли вам видеть сообщения об ошибках на экране своего компьютера? Обычно там пишут что-то вроде "Программа аварийно завершена... бла-бла-бла... Код -314." Вот это примерно тоже самое. Разница в том, что когда случаются проблемы операционная система нас об этом оповещает, а когда всё хорошо она нас лишний раз не беспокоит.

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

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

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

Вы можете спросить, а почему именно нуль? А чёрт его знает! Просто так обычно делают. Можно, в принципе, возвращать какое-нибудь другое целое число, например 100, или -236. Лишь бы оно было целым числом. Помните про int? Поэтому и целое.

Вот мы и разобрались с функцией main. Ещё один момент. То что записано в фигурных скобках обычно называют "тело функции" (или описание функции), а первую часть, та что перед фигурными скобками называется заголовок функции.

Вернёмся теперь к нашей первой программе "Hello, World" и посмотрим, что там к чему.

Листинг 5. Программа «Hello, World»

#include int main(void) { printf("Hello, World!\n"); return 0; }

Кое-что нам теперь уже понятно в этой программе. Не ясными остаются только две строки, пойдём по порядку.

Листинг 6. Директива include

#include

Данная строчка это сообщение компилятору. Такие сообщения, начинающиеся с символа #, называются директивами компилятора. Буквально: «подключи файл stdio.h». Во время компиляции вместо этой строчки вставится содержимое файла stdio.h. Теперь немного поговорим об этом файле. stdio.h (от англ. STanDart Input Output) это заголовочный файл, в нем описаны различные стандартные функции, связанные с вводом и выводом.

Возникает резонный вопрос "А зачем нам писать эту строчку? Зачем нам вообще понадобилось вставлять сюда этот файл?" Это нужно для того, что бы в своей программе, мы могли использовать стандартную функцию вывода на экран printf().

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

Так же и компилятор. Когда он встречает какую-нибудь функцию, он ищет её описание (т.е. что она должна делать и что обозначает) в начале программы (с самого начала и до момента её использования в программе). Так вот, функция printf() описана в файле stdio.h. Поэтому мы и подключаем его. А вот когда мы его подключим, компилятор сможет найти функцию printf(), иначе он выдаст ошибку.

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

Рис.3 Карта "Структура программ на языке Си." Блок подключения заголовочных файлов.

Продолжим разбираться с нашей программой.

Листинг 7. функция printf()

Printf("Hello, World!\n");

В этой строке мы вызываем стандартную функцию вывода на экран printf(). В данном простейшем случае мы передаем ей один параметр, строку, записанную в кавычках, которую надо вывести на экран, в нашем случае это Hello, World! \n. Но постойте, а что это за \n? На экране, во время запуска программы, никаких \n не было. Зачем тогда мы тут это написали? Данная последовательность это специальный символ, который является командой перейти на следующую строку. Это как в MS Word нажать клавишу Enter. Таких специальных символов несколько, все они записываются с помощью символа "\" - обратный слеш. Такие специальны символы называются управляющими символами. Потом я еще покажу вам их. В остальном на экране появится именно то, что вы написали в двойных кавычках.

Кстати, обратите внимание, каждая команда языка Си заканчивается символом «;» (точкой с запятой). Это похоже на точку в конце предложения, в русском языке. В обычном языке мы разделяем точкой предложения, а в языке программирования Си, точкой с запятой отделяем команды друг от друга. Поэтому ставить точку с запятой обязательно. Иначе компилятор будет ругаться и выдаст ошибку.

Чтобы вызвать какую-нибудь функцию, необходимо написать её имя и указать передаваемые ей параметры в круглых скобках. У функции может быть один или несколько параметров. А может не быть параметров вовсе, в таком случае в скобках писать ничего не нужно. Например, выше мы вызвали функцию printf() и передали ей один параметр строку, которую необходимо вывести на экран.

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

Листинг 8. Стандартная заготовка для программ на языке Си.

#include int main(void) { return 0; }

Ну вот вроде бы и всё. Этом первый урок можно считать законченным. Хотя нет, ещё один момент есть.

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


Исходный код программы-открытки есть в архиве с исходными кодами этого урока. Экспериментируйте! У вас всё получится.




Top