- •Оглавление
- •Введение
- •1Аппроксимация функции методом наименьших квадратов
- •1.1 Постановка задачи
- •1.2 Формализация задачи
- •1.3 Разработка алгоритма
- •1.4 Программирование
- •1.5 Анализ результатов
- •2Многомерная оптимизация
- •2.1 Постановка задачи
- •2.2 Формализация задачи
- •2.3 Разработка алгоритма
- •2.4 Программирование
- •2.5 Анализ результатов
- •Заключение
- •Библиографический список
1.4 Программирование
Ниже представлены листинги первой и второй программы. Файл с исходным кодом первой программы называется «dots_creator.cpp», а файл с исходным кодом второй – «approximation.cpp».
// file “dots_creator.cpp”
//------------------------------------------------------
#include <vcl.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#pragma hdrstop
// global variables
double disp;
// prototypes
double func(double x,int flag);
double nois(double sigma);
// functions
double func(double x, int flag)
{
double w;
int i;
w=x*x;
w=w+w*x+1/x+log10(x);
if(flag)
w+=nois(disp);
return w;
}
double nois(double sigma)
{
double s;
int j;
s=0.;
for(j=0;j<12;j++) s+=rand()/(double)RAND_MAX;
s-=6;
s*=sqrt(sigma);
return s;
}
//------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
FILE *fp;
double x,step,fnc;
int anr, dots,stime;
char cmd[2];
long ltime;
printf("f(x)=1/x+log10(x)+x^2+x^3\n");
printf("This function will be solved on interval from 0.1 to 1\n");
printf("How many dots do you need?: ");
while(1)
{
scanf("%d",&dots);
if(dots>0)
break;
printf("It must be a positive number. Try again: ");
}
printf("With nois? (y/n): ");
scanf("%s",cmd);
if(cmd[0]=='n' || cmd[0]=='N')
anr=0;
else
{
anr=1;
printf("Input a value of the dispersion: ");
scanf("%lf",&disp);
}
if((fp=fopen("dots.txt","wt"))==NULL)
{
printf("Failure: creating of the file was abortive\n");
return -1;
}
ltime=time(NULL);
stime=(unsigned) ltime/2;
srand(stime);
step=(1.-0.1)/dots;
fprintf(fp,"%d\n",dots);
for(x=0.1; x<1.; x+=step)
fprintf(fp,"%.16e %.16e\n", x, func(x,anr));
fclose(fp);
return 0;
}
//------------------------------------------------------
// file “approximation.cpp”
//------------------------------------------------------
#include <vcl.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include <alloc.h>
#pragma hdrstop
// global variables
int flag=0;
// prototypes
double **mrx_crt(int m, int n);
void mrx_del(double **mrx_tmp,int m);
void refresh(double **tmpmas,int m,int n);
int approx(double **tmpmas,int m,double **vecA,double **vecB);
double func(double x,int num);
void outmrx(double **tmp_mrx, int m, int n);
// functions
double func(double x,int num)
{
switch(num)
{
case 0: if(x!=0.)
return 1/x;
else
flag=1;
break;
case 1: return log10(x);
case 2: return x*x;
case 3: return x*x*x;
default: break;
}
return 0.;
}
int approx(double **tmpmas,int m,double **vecA,double **vecB)
{
int i,j,k;
double W,s;
for(k=0;k<m-1;k++)
{
for(i=k+1;i<m;i++)
{
W=tmpmas[i][k]/tmpmas[k][k];
for(j=k;j<m;j++)
tmpmas[i][j] -= W*tmpmas[k][j];
vecB[i][0] -= W*vecB[k][0];
}
}
W=1.;
for(i=0;i<m;i++)
W*=tmpmas[i][i];
W=floor(fabs(W));
if(W==0.)
return 1;
for(i=m-1;i>=0;i--)
{
s=0;
for(j=i;j<m;j++)
s += tmpmas[i][j]*vecA[j][0];
vecA[i][0]=(vecB[i][0]-s)/tmpmas[i][i];
}
return 0;
}
void refresh(double **tmpmas,int m,int n)
{
int i,j;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
tmpmas[i][j]=0.;
}
double **mrx_crt(int m, int n)
{
double **mrx_tmp;
int i,j;
mrx_tmp=(double **)farmalloc(m*sizeof(double *));
if(mrx_tmp!=NULL)
{
for(i=0;i<m;i++)
{
mrx_tmp[i]=(double *)farmalloc(n*sizeof(double));
if(mrx_tmp[i]==NULL)
{
for(j=i-1;j>=0;j--)
farfree(mrx_tmp[j]);
farfree(mrx_tmp);
mrx_tmp=NULL;
break;
}
}
}
return(mrx_tmp);
}
void mrx_del(double **mrx_tmp, int m)
{
int i;
if(mrx_tmp!=NULL)
{
for(i=0;i<m;i++)
if(mrx_tmp[i]!=NULL)
farfree(mrx_tmp[i]);
farfree(mrx_tmp);
}
}
void outmrx(double **tmp_mrx, int m, int n)
{
int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
printf("%18.16lf",tmp_mrx[i][j]);
}
printf("\n");
}
}
//------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
FILE *fp;
double **buff=NULL;
double **vecA=NULL, **vecB=NULL;
double arg, fcn,sum=0.;
int m=4,k,j,dots,shift;
if((buff=mrx_crt(m,m))==NULL)
{
printf("Program failure\n");
getch();
return -1;
}
if((vecA=mrx_crt(m,1))==NULL)
{
mrx_del(buff,m);
printf("Program failure\n");
getch();
return -1;
}
refresh(vecA,m,1);
if((vecB=mrx_crt(m,1))==NULL)
{
mrx_del(buff,m);
mrx_del(vecA,m);
printf("Program failure\n");
getch();
return -1;
}
refresh(vecB,m,1);
refresh(buff,m,m);
if((fp=fopen("dots.txt","rt"))==NULL)
{
mrx_del(buff,m);
mrx_del(vecA,m);
mrx_del(vecB,m);
printf("Not found the process file\n");
getch();
return -1;
}
fseek(fp,0L,SEEK_SET);
fscanf(fp,"%d",&dots);
while(feof(fp)==0)
{
fscanf(fp,"%lf%lf",&arg,&fcn);
for(k=0;k<m;k++)
{
for(j=k;j<m;j++)
{
buff[k][j]+=func(arg,k)*func(arg,j);
if(k!=j)
buff[j][k]=buff[k][j];
}
if(flag)
break;
vecB[k][0]+=func(arg,k)*fcn;
}
if(flag)
break;
}
fclose(fp);
if(flag)
printf("Happened breakpoint: problems with computing of the function\n");
else
{
if(approx(buff,m,vecA,vecB))
{
printf("Happened breakpoint: may be too little dots or Gauss method is inapplicable for this function\n");
printf("Your sample is %d dots\n",dots);
}
else
{
printf("Sample: %d dots\n",dots);
printf("Ratios:\n");
outmrx(vecA,m,1);
}
}
mrx_del(buff,m);
mrx_del(vecA,m);
mrx_del(vecB,m);
getch();
return 0;
}
//------------------------------------------------------
Первая программа построена на следующих «самостоятельных» функциях (не считая функцию main):
Функция double func(double x,int flag);
Функция double nois(double sigma).
Функция func возвращает значение функции (1.1). В качестве параметров функции нужно передавать значение аргумента и параметр flag, указывающий о необходимости зашумления значения возвращаемого результата. Зашумление будет происходить, если flag будет иметь ненулевое значение. Так как диапазон аргументов фиксирован, то в теле функции не предусмотрен возврат ошибок, связанных с вычислением значений функции.
Функция nois возвращает нормальную случайную величину с дисперсией, задаваемой sigma. Генерация случайного числа происходит с помощью генератора псевдослучайных чисел rand(), который возвращает числа с равномерным распределением. Исходное число, которое функция rand() использует для генерации последовательности, устанавливается один раз в теле main() с помощью функции srand(), которая использует для этого системное время.
В первой программе предусмотрено ветвление алгоритма рисунка 1.1, когда пользователь может решать зашумлять результат или нет. Для этого пользователь должен вводить по запросу латинскую букву y или n. Для простоты, в программе идет слежение только на отрицательный ответ, поэтому фактически для утвердительного ответа пользователь может использовать любой символ, кроме ‘n’ и ‘N’. Также предусмотрена простая защита на ввод отрицательного числа точек: если пользователь вводит отрицательное или нулевое число, то программа запросит число точек снова.
Так же в программе есть строка, не предусмотренная алгоритмом. Первым значением в файл записывается число точек, введенное пользователем. Так как это число ни на что не влияет в дальнейшем, то его можно считать дополнительным бонусом. Присутствие этого числа предусмотрено во второй программе.
При удачном завершении программы, она закрывается и в каталоге с программой должен появиться файл «dots.txt». При неудачном завершении, не связанным с созданием файла, файл тоже должен появиться. При этом он может быть пуст или в нём может быть только значение числа точек. Ошибка, связанная с созданием файла, перехватывается. Функция main возвращает 0 при удачном завершении и -1 при всех перехватываемых ошибках.
Вторая программа построена на следующих «самостоятельных» функциях:
double **mrx_crt(int m, int n);
void mrx_del(double **mrx_tmp,int m);
void refresh(double **tmpmas,int m,int n);
int approx(double **tmpmas,int m,double **vecA,double **vecB);
double func(double x,int num);
void outmrx(double **tmp_mrx, int m, int n).
Хотя по заданию размеры всех массивов предопределены и фиксированы, в данной реализации работа с массивами несколько унифицирована.
Функция mrx_crt возвращает указатель на двумерный массив размером m на n. Подразумевается, что функция вызывается корректно и параметры функции – натуральные числа. Функция выделяет память под массив в глобальной динамической памяти. В случае неудачи возвращает нулевой указатель NULL.
Функция mrx_del освобождает динамическую память, выделенную функцией mrx_crt. Функции необходимо передавать указатель на двумерный массив и количество строк этого массива. Подразумевается, что функция вызывается корректно и в её параметрах действительно указатель на двумерный массив с натуральным и реальным числом указателей на строки.
Функция refresh обнуляет все значения двумерного массива размером m на n. Подразумевается, что функция вызывается корректно и в её параметрах действительно указатель на двумерный массив с реальным размером. Функция не перехватывает ошибку, когда ей передают нулевой указатель. Необходимость данной функции обусловлена строкой «Ввод» в приведенных выше структурограммах.
Функция approx выполняет поиск параметров эмпирической формулы. Функции необходимо передавать указатель на двумерный массив формулы (1.5), количество строк массива и указатели на два вектора – vecA и vecB. Двумерный массив и свободный вектор должны быть подготовлены перед передачей согласно алгоритму рисунка 1.3. Вектор vecA специально может быть не подготовлен; именно в него запишутся параметры эмпирической формулы. Подразумевается, что функция вызывается корректно и указатели действительно на существующие массивы реального размера, так как такие ошибки не перехватываются. Данная функция целиком соответствует структурограмме рисунка 1.4. В случае удачи функция возвращает 0, а в vecA хранится результат, в противном случае функция возвращает -1. В любом случае следует помнить, что после вызова однозначно меняется структура передаваемого двумерного массива и свободного вектора.
Функция func соответствует эмпирической формуле (1.1). Функции нужно передавать аргумент и номер субфункции из (1.3). Можно передавать номера от 0 до 3, в противном случае func возвращает 0. Внутри предусмотрен перехват ошибки деления на ноль, при возникновении которой глобальная переменная flag принимает значение 1.
Функция outmrx выполняет вывод двумерного массива размером m на n. Функции передается указатель на массив и его реальные размеры. Подразумевается, что функция вызывается корректно и в неё действительно передаётся реальный указатель на массив и его реальные размеры.
Для простоты, во второй программе не предусмотрен «отлов» ошибки, когда файл пуст или в нем единственная строка. Ситуация, когда файла нет, перехватывается и выводится соответствующее сообщение. Алгоритм рисунка 1.3 выполняется внутри функции main. Функция main возвращает 0 в случае удачи и -1 при всех перехватываемых ошибках. В случае удачи на экран будут выведены параметры эмпирической формулы. Вектора в данной реализации создаются как двумерные массивы.