книги / Язык Си
..pdfРЕШЕНИЕ ЗАДАЧ
Задача 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.