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

Тема в разделе "C/C++/C#", создана пользователем ermackprogramis, 5 дек 2010.

  1. ermackprogramis

    ermackprogramis Гость

    Добрый вечер всем.Мне нужно решить уравнене 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");
    }
    И подскажите как сделать методом касательных.Зарание спасибо.
     
  2. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Используй тэги!
     
  3. ensane

    ensane Гость

    Недостатки кода:
    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. Он нынче оставлен скорее для совместимости, чем для реальных нужд.
     
  4. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    0. Это указатели. Хотя это и не критично.
     
  5. ensane

    ensane Гость

    См отредактированное сообщение.
     
  6. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Смотрю. И что я должен там увидеть? У тебя там так и написано "ссылки".
     
  7. ensane

    ensane Гость

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

    ermackprogramis Гость

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

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

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

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    ermackprogramis
    В теме ты про задание и слова не упомянул, т.ч. не обижайся. Он все верно сказал.
     
  10. ermackprogramis

    ermackprogramis Гость

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

    ensane Гость

    Первоначальный код содержал ошибки, сорри, писал в блокноте, отлаживал в уме. Вообще, если получаешь ошибки после копирования кода, кидай их из лога сюда. У меня 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.
     
  12. ermackprogramis

    ermackprogramis Гость

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

    ensane Гость

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

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    А почему ты считаешь что в solve_nr параметр start_point нужно передавать как указатель? За это пальцы не надо отрубать?
    И зачем ты в конце каждой функции кроме main() поставил точку с запятой?
    Текст будет читабельней, если в начале программы описать using namespase std; а из функций область видимости убрать.
     
  15. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    А вот помойму и дубль темы
     
Загрузка...
Похожие Темы - Задача Нелинейное уравнение
  1. Янчик
    Ответов:
    0
    Просмотров:
    479
  2. TrishaRay
    Ответов:
    1
    Просмотров:
    778
  3. elzim
    Ответов:
    0
    Просмотров:
    929
  4. ShaoKahn
    Ответов:
    0
    Просмотров:
    1.117
  5. eremin-sanek
    Ответов:
    3
    Просмотров:
    1.105

Поделиться этой страницей