Задача: Нелинейное уравнение.Метод касательных и перебора.

  • Автор темы ermackprogramis
  • Дата начала
E

ermackprogramis

#1
Добрый вечер всем.Мне нужно решить уравнене x=ln(x)+2 методом касательных и перебором.Последнее я вроде сделал но где то ошибка что оно не правильно считает.
Скаэите пожалуйста что в коде не так.Вот код:
C++:
#include <iostream>
#include <math.h>

using namespace std;

float h,x;

float f1(float *param)
{
if (*param==0)					 
*param+=h; 
return (*param-log(*param)-2); 
}

float f2(float *param2)
{
if(*param2==0)
*param2+=h;
return ((*param2+h)-log(*param2+h)-2);
}

void solution(float *a, float *с)
{
do{
{
x=*a;
if(f1(&x)*f2(&x)>0)
x=x+h;
}
}while(f1(&x)*f2(&x)<0);
}

int main()
{
cout<<"x=ln(x)+2"<<endl;
cout<<"Enter h"<<endl;
cin>>h;
float left,right;					 
cout<<"input a,с"<<endl;
cin>>left;
cin>>right;		 
float* pl=&left;
float* pr=&right;
solution(pl,pr);
cout<<"root = "<<x<<endl; 
system("pause");
}
И подскажите как сделать методом касательных.Зарание спасибо.
 
E

ensane

#3
Недостатки кода:
0. Ты не индус случайно?
1. Зачем везде передача через указатели?
2. Зачем две функции?
3. Где проверка на выход за пределы диапазона?
4. Зачем вместо double используешь float? Хотя это и не критично.


Как надо:
1) Тебе нужна только одна функция:
C++:
double f(const double x){
if(abs(x)<0.000001)x=0.000001;//ни в коем случае не h! можно случайно выплеснуть ребенка!
return (x - log(x) - 2);
}
2) Поиск решения:
C++:
double solution(const double a, const double c){
bool found = false;
x = a;
while(!found && (x<c)){
found = (f(x)*f(x+h)<0);
x+=h;
};
if(found)return x;//мы нашли результат
return 0;//или что-нибудь еще, что символизирует, что на данном отрезке решений нет
};
3) Метод касательных: Xk+1 = Xk - f(Xk)/f'(Xk)
Добавляем в код еще одну функцию, которая считает производную:
C++:
double df(const double x){
if(abs(x)<0.000001)x=0.000001;
return (1-1/x);
}
Сам процесс решения будет выглядеть следующим образом:
C++:
double solution(const double a, const double c){
bool found = false;
x = a;
xk = c;
while(abs(x-xk)>PRECISION){//заранее дефайним PRECISION как нужную нам точность решения
xk = x - f(x)/df(x);
};
return x;//мы нашли результат
//можно добавить счетчик итераций, чтобы не зависнуть. но с данной функцией - не должны
Дополнительные замечания: подключай не math.h, а cmath. В принципе, это одна и та же библиотека, но в некоторых олдскульных компиляторах можно нарваться на прелестную ситуацию, когда abs окажется функцией, работающей с целочисленными типами. Будет весело.
Забудь про float. Он нынче оставлен скорее для совместимости, чем для реальных нужд.
 

lazybiz

Well-known member
03.11.2010
1 339
0
#6
Смотрю. И что я должен там увидеть? У тебя там так и написано "ссылки".
 
E

ensane

#7
Блин. Не сохранилось :) Впрочем это действительно некритично
 
E

ermackprogramis

#8
Я не индус указатели потому что задание такое.Вот:

Найти корни нелинейного уравнения вида x=ln(x)+2 . Поиск приближенного значения хотя бы одного кореня уравненния f(x) = 0 на отрезке [a; b] вычислять методами перебора и касательных. У функцию, что реализируют алгоритмы, передавать указатели на тип float.

Добавлено: Спасибо за то, что написал хоть это
 

lazybiz

Well-known member
03.11.2010
1 339
0
#9
ermackprogramis
В теме ты про задание и слова не упомянул, т.ч. не обижайся. Он все верно сказал.
 
E

ermackprogramis

#10
Какие обиды?Ты что?Я просто говорю что задание такое.У меня никаких обид,наоборот спасибо за помощь.Но у меня когда я его код копирую и вставляю то пишет ошибку,Не могу понять где
 
E

ensane

#11
Первоначальный код содержал ошибки, сорри, писал в блокноте, отлаживал в уме. Вообще, если получаешь ошибки после копирования кода, кидай их из лога сюда. У меня libastral.dll не собралась.
Вот рабочий и проверенный код (MSVS 2008)
C++:
#include <iostream>
#include <cmath>
#define PRECISION 0.000001



float f(const float x){
if(abs(x)<PRECISION)return PRECISION-log(PRECISION)-2;
return x-log(x)-2;
};

float df(const float x){
if(abs(x)<PRECISION)return 1-1/PRECISION;
return 1-1/x;
};

bool search_solve(float *a, float *c, float *h, float *res){
bool found = false;
if(*a<0){
return false;//такую начальную точку задавать нельзя - она вне области определения функции
};
if(*c<*a){
return false;//ибо a - левая граница, а c - правая.
};
float x = *a;
while(!found && (x<*c)){
found = (f(x)*f(x+*h)<0);
x+=*h;
};
*res = x;//мы нашли результат
return found;//true - нашли ответ :); false - не нашли :(
};

bool solve_nr(float *start_point, float *res){
//метод касательных, он же метод Ньютона-Рафсона
if(*start_point < 0){
return false;//такую начальную точку задавать нельзя - она вне области определения функции
};
if(*start_point == 1){
return false;//такую начальную точку задавать нельзя - она вне области определения производной функции
};
float xk = *start_point;
float x;
do{
x=xk;
xk = x - f(x)/df(x);
}while(abs(x-xk)>PRECISION);
*res = x;
return true;//для данной функции (x=ln(x)+2) решение методом касательных найдется наверняка.
};

int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL,"Russian");

float a, c, h, res;

//ввод данных
std::cout << "Введите a:";
std::cin >> a;
std::cout << "Введите c:";
std::cin >> c;
std::cout << "Введите h:";
std::cin >> h;
//решаем методом перебора
std::cout << "Поиск решения методом перебора на отрезке [" << a << "," << c << "]:" << std::endl;
if(search_solve(&a, &c, &h, &res)){
std::cout << "решение: x=" << res << std::endl;
}else{
std::cout << "на указанном отрезке корней уравнения нет :(" << std::endl;
};
//... и методом касательных
std::cout << "Поиск решения методом касательных с начальной точки x0=" << a << std::endl;
if(solve_nr(&a, &res)){
std::cout << "решение: x=" << res << std::endl;
}else{
std::cout << "бида-бида!!! начальная точка совсем плохая!" << std::endl;
};

return 0;
}
Некоторые нюансы: если задать точку а равной 1 или меньше, возможны глюки. Но это - особенность логарифма, точнее - его производной. Поэтому лучше начинать отрезок с 2.
 
E

ermackprogramis

#12
Спасибо огромное,теперь только нужно это все перевести что бы были указатели.Пойду переводить
 
E

ensane

#13
Не спеши переводить! Собственно, указатели в коде везде, кроме функций f и df. Пихать указатели туда - верх маразма. ТАК ДЕЛАТЬ НЕЛЬЗЯ!
У функцию, что реализируют алгоритмы, передавать указатели на тип float.
Алгоритмы реализуют функции search_solve и solve_nr. В них как раз указатели и передаются.
А за указатели в f и df я бы сразу отрубал пальцы.
 

lazybiz

Well-known member
03.11.2010
1 339
0
#14
Алгоритмы реализуют функции search_solve и solve_nr. В них как раз указатели и передаются.
А почему ты считаешь что в solve_nr параметр start_point нужно передавать как указатель? За это пальцы не надо отрубать?
И зачем ты в конце каждой функции кроме main() поставил точку с запятой?
Текст будет читабельней, если в начале программы описать using namespase std; а из функций область видимости убрать.