Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Язык Си

..pdf
Скачиваний:
6
Добавлен:
20.11.2023
Размер:
7.64 Mб
Скачать

РЕШЕНИЕ ЗАДАЧ

Задача 1. Вычислить площадь выпуклого многоугольника.

Разобьем многоугольник на треугольники и просуммируем площади треугольников. Подзадачу определения площади тре­ угольника удобно оформить в функцию. Треугольник будем вы­ числять по заданным координатам вершин (см. лекцию 1, задача 2), которые будем передавать в функцию в виде массивов xtr и ytr. Отметим, что количество треугольников на два меньше, чем число вершин многоугольника.

#include<conio.h>

#include<stdio.h>

#include<math.h>

#define n 6 //число вершин многоугольника //задаем через макрос

double S_triangle(double х[],double у[]); main()

{double x[n]={0,3,4/5/1,0}; double y[n]={0,0,l,3,4,4}; double s=0,xtr[3],ytr[3] ; int i;

for(i=0;i<n-2;i++) //перебираем вершины //многоугольника

{//выделяем координаты текущего треугольника xtr[0]= х [i];

x t r [1]= x [i+1];

xt r [2]= x [n-1];

yt r [0]= y [i];

y t r [1]= y [i+1]; y t r [2]= y [n-1];

//суммируем площади треугольников s += S_triangle(xtr,ytr);

printf("%f",s ); getch();

return 0;

}

// Функция вычисления площади треугольника double S_triangle(double x[],double y[]) {double a,b,c,p,s;

a=hypot(x [1]- x [0],у [1]- у [0]); b=hypot(x [2]-x [1]/у[2]-у[1]); c=hypot(x [0] -x [2] ,у [0] -у [2] ); p=(a+b+c)/2;

s=sqrt(p*(p-a)* (p-b)* (p-c)); return s;

}

Задача 2. Определить, принадлежит ли точка треугольнику.

Если точка t принадлежит треугольнику с вершинами 1, 2, 3, то сумма площадей треугольников с вершинами 1, 2, t92, 3, t, 3, 1, t равна площади треугольника с вершинами 1, 2, 3:

Таким образом, здесь опять возникает подзадача нахождения площади треугольника:

#include<conio.h>

#include<stdio.h>

#include<math.h>

double S_triangle(double xO,double xl,

double x2,double yO,double yl,double y2);

main()

{//координаты треугольника

double х[3]={0,4,1}/У[3]={0,1,4}; double xt=0,yt=2; //координаты точки double s_tr,s_sum;

int i;

s_tr =

S_triangle(x[0],x[l],x[2],y[0],y[l] ,y[2] );

s_sum =

S_triangle(x[0],x [1],xt,у [0],у [1] ,yt); s_sum +=

S_triangle (x [1] ,x [2] ,xt, у [1] ,у [2] ,yt); s_sum +=

S_triangle(x[2],x [0], xt,у [2],у [0] ,yt); if(s_sum==s_tr)

printf("Точка принадлежит треугольнику"); else

printf("НЕТ");

getch(); return 0;

}

// Функция вычисления площади треугольника double S_triangle(double xO,double xl,

double x2,double y0,double yl,double y2) {double a,b,c,p,s;

a=hypot(xl-xO,yl-yO);

b=hypot(x2-xl,y2-yl); c=hypot(x0-x2,y0-y2); p=(a+b+c)/2;

s=sqrt(p*(p-a)* (p-b)* (p-c)); return s;

}

Очень часто при работе с числами с дробной частью накапли­ вается погрешность округления. В результате возможен вариант, что числа будут отличаться друг от друга, например, на несколько миллионных, и условие типа if(a~=b) уже не будет истинным. В этом случае можно применить другое условие

\a-b\ <8,

где 8 - очень маленькое число, например, 10_6. Если вы изменили значение координат точки на xt = 0.5, yt = 0.5 (точка принадле-* жит треугольнику), а программа печатает НЕТ, то причиной неправильного ответа является как раз этот случай. Замените в программе условие

i f (s_sum==s_tr)

на

i f (fabs(s_sum-s_tr)<le-6 )

Здесь (le-6) - это запись числа КГ6 в так называемом экспоненци­ альном формате, который часто используется в программирова­

нии.

2

Г JC

Задача 3. Вычислить интеграл —г---- -dx численно.

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

Идея многих методов численного интегрирования состоит в том, что вся область интегрирования а - b разбивается на п равных

отрезков длиной A = (b - а)/п и на каждом отрезке приближенно вычисляется площадь S(:

Таким образом, интеграл приближенно равен сумме площа­ дей S,:

j/(x )fifr* £ s,.

(9.1)

а'=1

Наиболее простыми формулами приближенного вычисления площади Sj являются следующие:

- формула прямоугольников S{= /(х,. + А / 2) • А;

,

^

fix ,) +/ (х + А)

А;

 

- формула трапеции

St =-— ■— -— -------

 

,

 

/( х .) + 4/(х. + А / 2) + /

(х. + А)

- формула парабол

 

Sj = ---------------- ------------------

 

--------А.

 

 

6

 

 

Здесь / - подынтегральное выражение (см. формулу (9.1)).

2

Итак, вычислим интеграл J — —— по трем данным фор­

мулам и сравним ответы. Подынтегральное выражение — ——

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

рования, шаг интегрирования (длина отрезка) по умолчанию зада­ дим 0.01.

#include<stdio.h>

#include<conio.h>

#include<math.h>

double rectangle(double,double,double=0.01); double trapezium(double,double,double=0.01); double parabola(double,double,double=0.01);

// Подынтегральное выражение double f(double x)

{ return x/pow(x*x+l,2);

}

// Главная функция main()

{printf ("S_rect=%f\nM,rectangle (-1,2, 0.1) );

//шаг по умолчанию

printf (f, _trap=%f\nM,trapezium(-l, 2) ); printf("S_parab=%fM,parabola(-1,2,0.1)); getch() ;

return 0;

}

//Вычисление интеграла по формуле //прямоугольников

double rectangle(double a,double b,double h) {double x=a,s=0;

while(x<=b)

{s+=f(x+h/2)*h;

x+=h;

}

return s;

}

// Вычисление интеграла по формуле трапеций double trapezium(double a,double b,double h) {double x=a,s=0;

while(x<=b)

{s+=(f(x)+f(x+h))/2*h;

x+=h;

}

return s;

}

// Вычисление интеграла по формуле парабол double parabola(double a,double b,double h) {double x=a,s=0;

while(x<=b)

{s+=(f(x)+4*f(x+h/2)+f(x+h))/6*h;

x+=h;

}

return s;

}

Результат на экране:

S_rect=0.149932

S__trap=0.150001

S_parab=0.150000

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

Задача 4. Запрограммировать функцию Бесселя первого рода первого порядка.

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

х 2 /4

(х2/4 )2

(х2/ 4)3 ( "

1 -

2!3!

3!4!

1!2!

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

х2 / 4, и номер первого из двух факториалов в знаменателе совпа­ дают с номером члена ряда, который содержится в переменной /. Факториал будем накапливать в переменную р, начальное значе­ ние которой зададим 1 (стандартно для накопления произведения). От члена к члену меняется знак. Для учета данной особенности введем переменную zn. Вычисленную сумму s при возвращении результата в точку вызова функции домножим на х / 2 .

Функцию Бесселя вычислим при х = -1.75 и десяти членах

ряда.

#include<conio.h>

#include<stdio.h>

#include<math.h>

double J1(double x, int n) {int i,zn;

double

s,p,x2;

s = 1; //подсчитали нулевой член ряда

Р

= 1; //начальное значение для накопления

zn

 

//факториала

= -1; //знак у первого члена ряда

х2

= х*х/4;

for(i=l;i<n;i++)

{p*=i;

//накапливаем факториал

s+=zn*pow(х2,i)/ (p*p*(i+l)); //накапливаем

zn*=-l;

//сумму ряда

//меняем знак у следующего члена

}

return s*x/2;

}

main()

{printf("%f",J1(-1.75,10) ); getch();

return 0;

}

Ответ: -0.580156.

Задача 5. Вычислить значение многочлена степени п в за­ данной точке х.

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

Пусть дан, например, многочлен третьей степени:

Р3(;с) = а0х3 +а1х2 + а2х + а3.

Его можно переписать как

х(а0х2+ tfjjc1+ а2) + а3= хР2{х) + а3.

В свою очередь, многочлен Р2{х) можно представить как

х(а0х1+а1) + а2=хР1(х) + а2.

Следуя данной аналог™ для представления многочлена сте­ пени п

р„(х) = а0х" +я,дс"'1+ а2х"~2 +... + ап,

можно записать общую формулу в виде

РЛ*) = хР„-1(х) + аП,

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

Р5(х )= 2х 5 - З х 4 + х 3 - 5 х + 3

в точке х = 1.45.

Коэффициенты многочлена удобно хранить в одномерном массиве а.

#include<stdio.h>

#include<conio.h>

double P(int n,double a [],double x)

{n— ;

if(n==0) //проверка на выход из рекурсии return a[n];

return x*P(n,a,x)+a[n];

}

main ()

{double a[6]={2,-3,1,0,-5,3},x=l.45; printf("%f\n",P (6,a,x));

getch(); return 0;

}

Ответ: -1.643426.