C++: РГР. Численные методы(4 части...)

24 мая 2004, понедельник 18:19
1. Экспоненциальная функция и её оптимизация.
1.1 Теоретическое обоснование метода


Для экспоненциальной функции справедливо разложение.

При x>>1 ряд сходится плохо, то есть для достижения нужной точности необходимо подсчитать большое количество членов ряда, что увеличивает время счета и приводит к возникновению проблемы вычислениях и i .
Стандартным приемом экономизации вычислений при суммировании степенных рядов является поиск зависимости вычисляемого слагаемого от предыдущего :

Для быстрой сходимости ряда представим:

X = p + q

p – целая часть х, => p = floor( x )
q - дробная часть х => q = x-p => q <1 =>



1.2 ГСА вычисления e^x с представлением x в виде суммы целой (p) и дробной (q) частей.


1.3 Программа на Си++

Описание переменных:

x – Степень в которую возводится е (экспонента)
e – Погрешность с которой будет высчитываться е в степени х
y_st – Результат расчёта е в степени х по стандартным библиотекам Си++
y – Результат расчёта е в степени х с помощью данного алгоритма
p – Целая часть х
q – Дробная часть х
ex – Значение е (экспоненты)
s – Переменная в которой накапливается сумма ряда
a – Переменная в которой хранится
i – Счётчик шагов цикла


Текст программы:
#include<stdio.h>

#include<conio.h>
#include<math.h>
void main()
{
float x,e,y_st,y,q,ex,s,a;
int i,p;
clrscr();
printf("Введите степень в которую будет возводится Exp,\nx=");
scanf("%f",&x);
printf("Введите точность с которой будет отыскиваться Exp в степени х,\n E=");
scanf("%f",&e);
p=floor(x); //Выделение целой части х - p
q=x-p; //Выделение дробной части х - q
ex=exp(1);
y=1;
i=1;
if(x)
{
if(p)
{
do
{
y*=ex;
i++;
}
while(i<=fabs(p));
if(p<0)
y=1/y;
else;
}
else;
if(q)
{
s=1;
a=1;
i=1;
do
{
a*=q/i;
s+=a;
i++;
}
while(fabs(a)>=e/y);
y*=s;
}
else;
}
else;
y_st=exp(x);
printf("\nРасчетное значение Exp в степени %g равно %f",x,y);
printf("\nЗначение Exp в степени %g по стандартной библиотеке Си равно %f",x,y_st);
getch();
}

1.4 Контрольные примеры к программе.


1.5 Вывод:
Расчет экспоненты в степени Х путём разложения в ряд имеет серьёзный недостаток: при значении степени много большем чем единица, достижение нужной точности требует больших вычислений, а следовательно времени и ресурсов. Разложение степени на целую и дробную часть и последующая оптимизация алгоритма, приводят к значительному уменьшению количества выполняемых операций и к быстрой сходимости ряда при заданной точности. Но при больших значениях степени возникает погрешность вычислений. Абсолютная погрешность в таком случае достаточно велика по сравнению со значением экспоненты, но относительная погрешность находится на достаточно низком уровне.
////////////////////


2. Синус и косинус
2.1 Теоретическое обоснование метода


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

для косинусоидальной функции:

Хотя интервал сходимости этого ряда , его суммирование при больших X связано с преодолением серьезных трудностей.
При х>>1 ряд сходится плохо, то есть для достижения нужной точности необходимо подсчитать большое количество членов ряда, что увеличивает время счета и приводит к возникновению проблемы вычисления и i! при больших i.
Стандартным приемом экономизации вычислений при суммировании степенных рядов является поиск зависимости вычисляемого слагаемого от предыдущего Для синусоидального и косинусоидального рядов такая зависимость:

Для улучшения сходимости степенного ряда уменьшим Х до диапазона [0;2*П], используя формулы приведения.

2.2 ГСА вычисления Sin Cos


///////////////////////////////////////////////////////////////////////////////////


2.3 Программа на Си++
Описание переменных:


x – Значение угла
p – Значение П = 3.14…
e – Точность расчётов
origx – Значение угла в радианах до преобразования
t – Первое и последующие слагаемое в ряде разложения тригонометрической функции
y – Значение рассчитанной тригонометрической функции
st_y – Значение тригонометрической функции по стандартным библиотекам Си++
k – Переменная от которой зависит знак i-того члена последовательности в ряде разложения тригонометрической функции
i – Номер члена последовательности в ряде разложения тригонометрической функции
f – Переменная в которой записывается, что нужно вычислять, синус или косинус
sis – Переменная в которой записывается, в какой единице измерения введено значение угла
znc, zns – Переменные в которые записывается знак триг. ф-ии при её преобразовании
priv( x, *sis, *origx, *p, *znc, *zns) – Функция преобразования угла.
s_c( x, e, t) – Функция вычисления суммы ряда разложения тригонометрической функции


Текст программы:
#include<conio.h>

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
float x,p=M_PI,e,origx,t,y_st,s,y;
int k,i,f,sis,znc=1,zns=1;
//////////////////////////////////////////////////////////////////////
float priv(float x, int *sis, float *origx, float *p, int *znc, int *zns)
{
if(*sis) x*=(*p)/180;
else;
*origx=x;
x=fmod(x,2*(*p));
if(x<0)
x=x+2*(*p);
else;
if(x>*p)
{
x=x-*p;
*zns=-1;
}
else;
if(x>*p/2)
{
x=*p-x;
*znc=-1;
}
else;
return x;
}
//////////////////////////////////////////////////////////////////////
float s_c(float x,float e,float t)
{
k=-1;
s=0;
if(t==1) i=0;
else i=1;
for(;fabs(t)>e;i+=2)
{
s+=t;
t=t*k*x*x/(i+1)/(i+2);
}
return s;
}
//////////////////////////////////////////////////////////////////////
void main()
{
clrscr();
printf("Требуется вычислить SIN(1),COS(2)?");
scanf("%d",&f);
printf("Угол задан в радианах (0), градусах (1)?");
scanf("%d",&sis);
printf("Введите угол:\n");
scanf("%f",&x);
printf("Введите точность рассчёта e:\n");
scanf("%f",&e);
x=priv(x,&sis,&origx,&p,&znc,&zns);
switch(f)
{
case 1: y_st=sin(origx);
if(x<p/4)
y=s_c(x,e,x);
else
{
x=p/2-x;
y=s_c(x,e,1);
}
y=zns*y;
break;
case 2: y_st=cos(origx);
if(x<p/4)
y=s_c(x,e,1);
else
{
x=p/2-x;
y=s_c(x,e,x);
}
y=znc*zns*y;
break;
}
printf("Результат вычисления функции по данному алгоритму %g\n",y);
printf("Результат вычисления функции по библиотекам Си %f",y_st);
getch();
}


2.4 Контрольные примеры к программе.

////////////////////


3. Нахождения корня функции на отрезке [a,b] методом дихотомии и простой итерации.

3.1.1 Теоретическое обоснование метода дихотомии.




3.1.2 Теоретическое обоснование метода простой итерации.



3.2.1 ГСА для нахождения корня функции на отрезке [a,b] методом дихотомии.


3.2.2. ГСА для нахождения корня функции на отрезке [a,b] методом простой итерации.


3.3 Программа на Си++

Описание переменных:
x – Искомый корень данной функции.
a – Координата начала отрезка
b – Координата конца отрезка
e – Точность расчёта х
k – Коэффициент, стоящий при функции для её сходимости (для итерации)
n – Максимальное число итераций (для итерации)
fun(x) – Функция в которой выполняется F(x)
dihot(*a,*b,e) – Функция реализации метода дихотомии
iter(a,b,k,n,e,*x0) – Функция реализации метода простой итерации.


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

Текст программы:
#include<conio.h>

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
float x0,x,a,b,e,n,k;
int v=0,s,err=0;
//////////////////////////////////////////////////////////////////////
float fun(float x)
{
float f;
f=x*x*x-4;
return f;
}
//////////////////////////////////////////////////////////////////////
float dihot(float *a,float *b, float e)
{
if(fun(*a)*fun(*b)<0)
{
do
{
if(fabs(fun(x))>=e)
{
x=*a+*b)/2;
if(fun(*b)*fun(x)<0)
*a=x;
else
*b=x;
}
else
v=1;
}
while(fabs(*b-*a)>e&&v==0);
}
else err=1;
return x;
}
//////////////////////////////////////////////////////////////////////
float iter(float a, float b, float k, float e, int n,float *x0)
{
int i=0;
x=(a+b)/2;
i=0;
do
{
*x0=x;
x=x+k*fun(*x0);
i++;
}
while(fabs(x-*x0)>e&&i<n);
return x;
}
//////////////////////////////////////////////////////////////////////
void main()
{
clrscr();
printf("Введите координаты отрезка [a,b] \n a=");
scanf("%f",&a);
printf(" b=");
scanf("%f",&b);
printf("Введите точность расчета \n e=");
scanf("%f",&e);
printf("Расчитать Х с помощью дихотомии(1) или итерации(2)?");
scanf("%i",&s);
switch(s)
{
case 1: dihot(&a,&b,e);
break;
case 2:printf("Введите коэффициэнт К \n К=");
scanf("%f",&k);
printf("Введите максимальное число итераций \nn=");
scanf("%f",&n);
iter(a,b,k,e,n,&x0);
break;
}
puts("/////////////////////////////////////////////////////////");
if(err)
{
printf("\n Ошибка! Код=%i",err);
printf("\n\n\n Расшифровка кода окибки:\n Код=1 - На данном отрезке корней нет");
}
else
printf("\n Расчитанный корень равен \n Х=%g",x);
getch();
}


3.4.1 Контрольный пример к программе. Метод дихотомии.
Функция у=х3-8



3.4.2 Контрольный пример к программе. Метод простой итерации.
Функция у=х3-8



////////////////////


4. Модуль, содержащий процедуру интерполяции полиномом Лагранжа.

4.1 Теоретическое обоснование метода

Аппроксимация функций.
Из курса математики известны 3 способа задания функциональных зависимостей:
1)аналитический
2)графический
3)табличный
Табличный способ обычно возникает в результате эксперемента.
Недостаток табличного задания функции заключается в том, что найдутся значения переменных которые неопределены таблицей. Для отыскания таких значений определяют приближающуюся к заданной функцию, называемой аппроксимирующей, а действие замены аппроксимацией.
Аппроксимация заключается в том, что используя имеющуюся информацию по f(x) можно рассмотреть другую функцию ф(x) близкую в некотором смысле к f(x), позволяющую выполнить над ней соответствующие операции и получить оценку погрешность такой замены.



4.2 ГСА для интерполяции полиномом Лагранжа.


4.3 Программа на Си++

Описание переменных:
size – Максимальное количество элементов в массиве x, y => Максимальное число точек
p – Переменная в которой накапливается произведение отношений (x – xj) к (xi -xj)
L – Переменная в которой копится сумма произведений yi и p. В итоге - это значение полинома (Y - ордината) в искомой точке
xd – Абсцисса (координата Х) искомой точки
x[size] – массив в котором хранятся значения координаты Х введённых точек
y[size] – массив в котором хранятся значения координаты Y введённых точек
i, j – Счётчики шагов во внутреннем и внешнем циклах
k – Количество введённых точек

Текст программы:
#include<stdio.h>

#include<conio.h>
#include<math.h>
#define size 20
void main()
{
float L,p,xd,x[size],y[size];
int i,j,k;
clrscr();
printf("Сколько будет точек?\nk=");
scanf("%i",&k);
for(i=0;i<k;i++)
{
printf("\n Введите координаты %i точки\n",i+1);
printf("x%i=",i+1);
scanf("%f",&x[i]);
printf("y%i=",i+1);
scanf("%f",&y[i]);
}
printf("\nВведите координату X искомой точки\n X=");
scanf("%f",&xd);
L=0;
for(i=0;i<k;i++)
{
p=1;
for(j=0;j<k;j++)
{
if(i==j);
else
p*=(xd-x[j])/(x[i]-x[j]);
}
p*=y[i];
L+=p;
}
printf("Координата Y искомой точки \n Y=%g",L);
getch();
}

4.4 Контрольный пример к программе.


4.5 Вывод:
Интерполяцией называется построение функции j(x), приближённой к искомой f(x), совпадающей с f(x) в данных узлах (точках). Большую степень приближения интерполирующей функции к искомой, а следовательно более приближённое значение функции, можно получить при использовании большего числа точек для построения интерполирующей функции. Но всё-таки единственное, что гарантированно, так это то, что полученный полином и искомая функция совпадают в узлах.
Интерполяция полиномом Лагранжа применяется для нахождения значения функции j(x), приближённой к искомой f(x), в точке с абсциссой Х. На мой взгляд этот метод можно применять только когда абсцисса искомой точки лежит на отрезке, составленном из абсцисс заданных точек. При таком положении искомой точки, будет наблюдаться приближение полученной при интерполяции функции j(x) к искомой f(x), а следовательно и уменьшение погрешности при использовании этого метода, так как в узлах значения функций совпадают. Если же абсцисса искомой точки не лежит на этом отрезке, а тем более если она сильно удалена от него, то сказать что значение j(x) в этой точке будет приближённо равно f(x) нельзя. Наоборот, можно с большой долей уверенности сказать, что в таком случае погрешность будет очень большой. Всё это доказывает приведённый мною пример. Я думаю, то же можно сказать и в случае когда заданные точки сильно удалены друг от друга.

Writen by Alex-Kirienko aka 4upuk


///////////////////////////////////////////////
Вот на этом моя "эпоея" и заканчивается, как говорится "а кто слушал - молодец" ^_^ Вот ТУТ лежит вся РГР(4 части) в *.doc. Может кому-нибудь и пригодиться... За сим и откланиваюсь...
///////////////////////////////////////////////
Мне armadillo дал свои "Занимательные задачи на С++ с решениями..."
Скоро выйдет, будет несколько частей.

Оценитe материал

Возможно вас заинтересует

Популярные новости

Сейчас обсуждают