Форум программистов, компьютерный форум CyberForum.ru

Решение нелинейного уравнения. Метод хорд и касательных - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 36, средняя оценка - 4.69
Iworb
анимешник++
 Аватар для Iworb
93 / 60 / 2
Регистрация: 03.11.2009
Сообщений: 411
22.04.2011, 22:42     Решение нелинейного уравнения. Метод хорд и касательных #1
Написал я программку для решения, но вот незадача:
Не находит их на некоторых отрезках.
Уравнение: ln(x+1)-p/(x^2)=0
p = -1...1
(т.е. 20 уравнений)
Вот класс, реализующий это решение:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
typedef double(*foo)(double,double);
 
typedef struct _item
{
    double a,b,p,x;         //[a,b] - интервал, на котором есть корень для уравнения с параметром p. Решение - x
}item;
 
double f(double x, double p)
{
    return log(x+1)-p/(x*x);
}
 
class HK
{
    private:
        foo f;              //функция по которой считаем
        double c,d;         //границы
        int n;              //на сколько разбиваем
        double eps;
        vector<item> s;
        double df(double x, double p);
        double ddf(double x, double p);
        item m(vector<item> x, int f=-1);   //f=1 - максимум, f=-1 - минимум
    public:
        HK(foo function, double c=-1, double d=1, int n=20, double e=0.01);
        vector<item> solve();
        double clarify(double a, double b, double p);
};
 
    HK::HK(foo function, double c, double d, int n, double e)
    {
        f=function;
        this->c=c;
        this->d=d;
        this->n=n;
        eps=e;
        s.clear();
    }
 
    double HK::ddf(double x, double p)
    {
        double dx=pow(10.0,-6);
        return (((f)(x,p)-2*(f)(x-dx,p)+f(x-2*dx,p))/(pow(dx,2)));
    }
 
    double HK::df(double x, double p)
    {
        double dx=pow(10.0,-6);
        return (((f)(x+dx,p)-(f)(x,p))/dx);
    }
 
    item HK::m(vector<item> x, int f)
    {
        item r;
        r.x=(-f)*32000;
        for(int i=0;i<x.size();i++)
            if(f*x[i].x>f*r.x) r=x[i];
        return r;
    }
 
    double HK::clarify(double a, double b, double p)
    {
        double x=(a+b)/2;
        while(fabs(a-b)>eps)
        {
            double ai=a, bi=b;      //старые значения - нужны для расчета новых
            if(df(x,p)*ddf(x,p)>0)
            {
                a=ai-((f)(ai,p)*(bi-ai))/((f)(bi,p)-f(ai,p));
                b=bi-((f)(bi,p))/(df(bi,p));
            }
            else
            {
                a=ai-((f)(ai,p))/(df(ai,p));
                b=bi-((f)(bi,p)*(bi-ai))/((f)(bi,p)-f(ai,p));
            }
            x=(a+b)/2;
        }
        return x;
    }
 
    vector<item> HK::solve()
    {
        double h=(d-c)/n;           //шаг p
        vector<item> x_all;     //вектор всех корней
        for(double p=c;p<=d;p+=h)   //для каждого p от с до d
        {
            x_all.clear();
            for(double x=-2;x<=2;x+=0.2)//бесконечный цикл нахождения корня, начиная от -2. Ищем интервалы по 0.2 и корень в нём
            {
                double a=(f)(x,p), b=(f)(x+0.2,p), a_d=df(x,p), b_d=df(x+0.2,p);
                if((fabs(a-b)>fabs(a+b))&&(fabs(a_d-b_d)<fabs(a_d+b_d)))
                //если знаки разные, то корень есть, а если производная не меняет свой знак - корень один
                //если на интервале [x;x+0.2] есть корень, то его нужно уточнить методом хорд и касательных
                //и занести в значения x_all
                {
                    item temp;
                    temp.a=x;
                    temp.b=x+0.2;
                    temp.p=p;
                    temp.x = clarify(a,b,p);
                    x_all.push_back(temp);
                }
            }
            //если корень не один, то отдаем предпочтение положительным. Если все корни одного знака - наибольшего по модулю
            if(x_all.size()>1)
            {
                vector<item> less, large;
                less.clear(); large.clear();
                for(int i=0;i<x_all.size();i++)
                {
                    if(x_all[i].x<0) less.push_back(x_all[i]);
                    else large.push_back(x_all[i]);
                }
                x_all.clear();
                if(!large.size())
                    x_all.push_back(m(less,-1));
                else
                    x_all.push_back(m(large,1));
            }
            s.push_back(x_all[0]);
        }
        return s;
    }
помогите пожауйста отладить функцию clarify - выдаёт много неправильных значений, но сработало при значениях (-0.8,-0.7,-1) вполне правильно. Ошибка связана с логирафимом - там x>-1 должен быть. Но он и так должен быть >-1, просто со временем интервал [a;b] при уточнение расширяется, а не сужается как надо.
Кому нужно - даю ссылку на сам метод

Добавлено через 17 минут
вроде как отработала нормально, потестил solve, вот что выдало:
| a| b| pi| x|
---------------------------------------------
|-0.8000000|-0.6000000|-1.0000000|-1.#IND000|
|-0.8000000|-0.6000000|-0.9000000|-1.#IND000|
|-0.8000000|-0.6000000|-0.8000000|-1.#IND000|
|-0.8000000|-0.6000000|-0.7000000|-1.#IND000|
|-0.8000000|-0.6000000|-0.6000000|-0.7029787|
|-0.8000000|-0.6000000|-0.5000000|-1.#IND000|
|-0.8000000|-0.6000000|-0.4000000|-0.6316026|
|-0.6000000|-0.4000000|-0.3000000|-1.#IND000|
|-0.6000000|-0.4000000|-0.2000000|-1.#IND000|
|-0.6000000|-0.4000000|-0.1000000|-0.4249508|
| 0.4000000| 0.6000000| 0.1000000|-1.#IND000|
| 0.6000000| 0.8000000| 0.2000000|-1.#IND000|
| 0.6000000| 0.8000000| 0.3000000|-1.#IND000|
| 0.8000000| 1.0000000| 0.4000000| 0.8180327|
| 0.8000000| 1.0000000| 0.5000000|-1.#IND000|
| 0.8000000| 1.0000000| 0.6000000|-1.#IND000|
| 1.0000000| 1.2000000| 0.7000000|-1.#IND000|
| 1.0000000| 1.2000000| 0.8000000|-1.#IND000|
| 1.0000000| 1.2000000| 0.9000000|-1.#IND000|
| 1.0000000| 1.2000000| 1.0000000|-1.#IND000|
---------------------------------------------
как видно - на многих участках работает неправильно(

Добавлено через 14 минут
проверил отдельно: при (-0.8,-0.6,-1) clarify выдает правильное значение, но вот в solve что-то происходит, что делает его неправильным.
Пока заметил, что вместо -0.8, -0.6 передается число ака -0.80000000063 - т.е. что-то в последних битах еще есть. Не знаете как это побороть?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.04.2011, 22:42     Решение нелинейного уравнения. Метод хорд и касательных
Посмотрите здесь:

МЕТОД ХОРД И КАСАТЕЛЬНЫХ C++
Комбинированный метод хорд и касательных C++
Комбинированный метод хорд и касательных. C++
C++ Комбинированный метод хорд и касательных
решение нелинейного метода хорд . ПОМОГИТЕ с програмой не работает C++
C++ Решение нелинейного уравнения в общем виде, ввод с клавиатуры, метод дихотомии
Нахождения корней уравнения: метод половинного деления (бисекции) или метод хорд C++
Метод хорд, касательных, золотого сечения C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Iworb
анимешник++
 Аватар для Iworb
93 / 60 / 2
Регистрация: 03.11.2009
Сообщений: 411
22.04.2011, 22:48  [ТС]     Решение нелинейного уравнения. Метод хорд и касательных #2
блин, выглядит, словно пообщался сам с собой, но я нашел ошибку, она была тут:
C++
1
2
3
4
5
6
item temp;
                    temp.a=x;
                    temp.b=x+0.2;
                    temp.p=p;
                    temp.x = clarify(temp.a,temp.b,p);
                    x_all.push_back(temp);
Кому нужно - добавляю полный код программы - авось пригодится.
Вложения
Тип файла: 7z main.7z (2.3 Кб, 173 просмотров)
Wins_Vega
0 / 0 / 0
Регистрация: 29.01.2011
Сообщений: 9
18.05.2011, 23:55     Решение нелинейного уравнения. Метод хорд и касательных #3
Arigato godzaimasu! Tasuketta arimashita.
Реально помогло. задание сдавать надо. а тут почти все готово. пару строк переделал и пошел сдал.
Только дллку еле нашел где скачать.
Yandex
Объявления
18.05.2011, 23:55     Решение нелинейного уравнения. Метод хорд и касательных
Ответ Создать тему

Метки
c++, метод хорд и касательных, уточнение корней
Опции темы

Текущее время: 20:35. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru