На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! правила раздела Алгоритмы
1. Помните, что название темы должно хоть как-то отражать ее содержимое (не создавайте темы с заголовком ПОМОГИТЕ, HELP и т.д.). Злоупотребление заглавными буквами в заголовках тем ЗАПРЕЩЕНО.
2. При создании темы постарайтесь, как можно более точно описать проблему, а не ограничиваться общими понятиями и определениями.
3. Приводимые фрагменты исходного кода старайтесь выделять тегами code.../code
4. Помните, чем подробнее Вы опишете свою проблему, тем быстрее получите вразумительный совет
5. Запрещено поднимать неактуальные темы (ПРИМЕР: запрещено отвечать на вопрос из серии "срочно надо", заданный в 2003 году)
6. И не забывайте о кнопочках TRANSLIT и РУССКАЯ КЛАВИАТУРА, если не можете писать в русской раскладке :)
Модераторы: Akina, shadeofgray
  
> Алгоритм решения уравнения методом итераций (простых) , ЯП - Си
    Всем хай! Сходу к делу!
    Условие задачи: найти приближенное значение корня функции 5*x - 8*ln(x) - 8, используя метод итераций.
    Как я понимаю, нужно сначала определить отрезки, на которых в принципе есть корни. Это можно делать аналитически и графически. График получил (см.рис.), видно, что есть 2 корня на отрезка, например: x(left) = [0.1; 1.2], x(right) = [2; 7].

    Прикреплённая картинка
    Прикреплённая картинка


    Смысл итераций в том, чтобы получить уравнения вида x = g(x). Для заданной функции будет так:
    x = 8/5 * (ln(x) + 1)
    Затем берем х0 и получаем х1: x1 = g(x0), потом x2 = g(x1), x3 = g(x2), ..., xn = g(xn-1).
    Процесс заканчивается, когда модуль(xn - xn-1) <= EPS, EPS - заданная точность расчета.

    Написал программу на СИ(вроде простая):
    ExpandedWrap disabled
      #include <stdio.h>
      #include <math.h>
      #include <conio.h>
      #include <locale.h>
       
      #define EPS 0.001       // точность расчета
       
      // f(x) = 5x - 8*ln(x) - 8
      // 5x = 8ln(x) + 8, x = 8/5 * (ln(x) + 1)
      double F(double px)
      {
          return (8.0 / 5.0 * (log(px) + 1));
      }
      void main(void)
      {
          double a = 2, b = 6;
          double x0, xn;
          setlocale(LC_ALL, "");
          x0 = xn = (b - a) / 2.0;
          do
          {
              x0 = xn;
              xn = F(x0);
          } while (fabs(xn - x0) > EPS);
          printf("Приближенное значение корня = %5.3f", xn);
          _getch();
          return;
      }


    И вроде бы все хорошо, но НЕ ПОЛУЧАЕТСЯ НИКАК получить самый левый корень :(
    Если отрезок [2; 6] - правый корень прекрасно определяется
    Если отрезок [0.1; 10] - определяется правый корень (но по идее такой отрезок задавать нельзя)
    Если отрезок [0.1; 1] = -nan(ind) - т е бред, переполнение или деление на ноль или еще чего-то нехорошее...а ведь там есть корешок нужный.

    Вопросы (просьба ответить на все, кто знает):
    1. значение х0 для 1-й итерации можно брать по середине отрезка [a, b] или можно начинать с границы а или в любом месте отрезка [a, b]?
    2. существуют еще немного др.алгоритм метода пр.итераций, когда вводится стягивающий коэфф. "М". Означает ли это, что для моей функции текущий алгоритм неоптимален?
    3. нужно ли анализировать тип функции, прежде, чем применять пр.итерации? Для своей ф-ции я взял самый простой вариант через рекуррентные соотношения
    4. а вообще, вот эти границы отрезка [a; b] влияют на что? лишь на стартовое х0 или достаточно, чтобы на этом отрезке был корешок? ведь в самом алгоритме границы не используются...
    5. или я вообще сделал все неправильно здесь?)

    Спс. за внимание
    Сообщение отредактировано: FasterHarder -
      С чего ты вообще взял, что данный итерационный процесс сойдётся?
        Цитата OpenGL @
        С чего ты вообще взял, что данный итерационный процесс сойдётся?

        ну, я как бы это, ну, наверное, не думал об этом) типа есть рекуррентная формула и все

        какие условия должны выполняться для сходимости?
          Производная g(x) должна быть не выше 1 (по модулю). У вас же она равна 8/(5*x), и в третьем случае (0,1...1) сильно вылетает-с. ;)

          Добавлено
          Ответы на вопросы:
          1. Можно брать где угодно, в области сходимости метода.
          3. Очевидно, что нужно. Выше я написал (про производную).
          4. На желаемое стартовое. Чем шире возможность применения - тем лучше (обычно). :)
              Цитата FasterHarder @
              Смысл итераций в том, чтобы получить уравнения вида x = g(x). Для заданной функции будет так:
              x = 8/5 * (ln(x) + 1)

              Смысл МПИ именно в том, чтобы найти ПРАВИЛЬНУЮ g(x), которая обеспечивает сходимость при любом начальном значении. Как показывает ТВОЯ практика, выбранная функция неудачна.
                Всем отписавшим выше спс. за ответы!
                В итоге, полез в ВИКИ читать описание и решил улучшить проггу) но не получилось все равно(

                Итак, дана ф-ция f(x) = 5x - 8Ln(x) - 8
                читаем алгоритм Вики дальше:
                Прикреплённая картинка
                Прикреплённая картинка

                Ок, выражаем х: x = 8/5 * (ln(x) + 1) = 8 * ln(x) / 5 + 8/5

                читаем алгоритм из Вики дальше:
                Прикреплённая картинка
                Прикреплённая картинка


                Ок, нужна производная заданной функции, но проблем:
                f'(x) = 5 - 8 * 1/x + 0 = 5 - 8/x

                читаем алгоритм из Вики дальше (посл.часть, ура, наконец-то таки):
                Прикреплённая картинка
                Прикреплённая картинка

                Т е лямбда0 вычислим 1 раз да и все)

                В итоге, такая получилась программа (она написана СТРОГО по приведенному алгоритму):
                ExpandedWrap disabled
                  #include "stdafx.h"
                  #include <stdio.h>
                  #include <math.h>
                  #include <conio.h>
                  #include <locale.h>
                  #define EPS 0.001       // точность расчета
                   
                   
                  // f'(x) = 5 - 8 * 1/x  + 0 = 5 - 8/x - производная заданной функции
                  double F_shtrih(double px)
                  {
                      return (5 - 8.0 / px);
                  }
                   
                  // f(x) = 5x - 8*ln(x) - 8
                  // 5x = 8ln(x) + 8
                  // x = 8/5 * (ln(x) + 1) = 8 * ln(x) / 5 + 8/5
                  double F(double px)
                  {
                      return (8.0 / 5.0 * (log(px) + 1));
                  }
                  void main(void)
                  {
                      double x0, xn;
                      double lyambda_0;
                      double a, b;
                      setlocale(LC_ALL, "");
                      printf("Введите границы (2 дробных числа через пробел), где находится корень уравнения: ");
                      scanf_s("%lf %lf", &a, &b);
                      printf("Введите приближенное значение корня из отрезка [%0.2f .. %0.2f]: ", a, b);
                      scanf_s("%lf", &x0);
                      // вычисляем ЛЯМБДА0 через производную заданной ф-ции
                      lyambda_0 = 1.0 / F_shtrih(x0);
                   
                      xn = x0 - lyambda_0 * F(x0);
                      while (fabs(xn - x0) > EPS)
                      {
                          x0 = xn;
                          xn = x0 - lyambda_0 * F(x0);
                      }
                   
                      printf("\nПочти точное значение корня = %5.3f", xn);
                      _getch();
                      return;
                  }


                и получаем ПЛАЧЕВНЫЙ результат :) :(
                Прикреплённая картинка
                Прикреплённая картинка


                в общем правильно НИЧЕГО не работает...
                Вот что я делаю НЕ ТАК?

                P.S. если честно, то я НЕ понимаю этот алгоритм, но это не должно мешать мне его закодировать)...
                  Ну так нет же ничего удивительного! У вашей функции f(x) в нуле полюс (особая точка), выброс из области определения. Метод же касательных подразумевает адекватное поведение f(x) на всей вычисляемой области. У вас разрыв - и метод рвётся. Всё норм, сколь бы нежелательно сие ни звучало. :yes:

                  Добавлено
                  П.С. мало какие методы решения работают на рваных ООФ (область определения функции), ибо это жесть жесточайшая. Зная таковое, вы могли бы проверять на каждой итерации возможность вылета за ООФ, и при свершении такового - подробить на кусочки и попытаться позапускать из других x0 (в данном случае - очевидно токмо близкие к 0 спасут).
                    Славян, вот смотри:
                    1. Область определения заданной ф-ции: x > 0 (ограничение задает натур.лог.)
                    2. Область определения производной ф-ции: x <> 0 (на 0 делить нельзя)

                    затем в проге я задаю границы по Х, всегда числа положительные + прибл.значение х0 - также плюсовое значение

                    1. ты ссылаешься на х = 0, а разве он тут возникает вообще?
                    2. т е алгоритм закодирован корректно?
                      Не совсем. Когда вы делите на производную (коя отрицательна) у вас происходит вылет за 0. И код норм, и ноль не получается, но вы покидаете непрерывную ООФ.

                      Добавлено
                      П.С. не совсем "делите на производную", а "-λ*f(x)", само собой.
                        Славян, я кажись понял о чем ты

                        проблема в этой строке, да?
                        ExpandedWrap disabled
                          xn = x0 - lyambda_0 * F(x0);


                        т е на какой-то итерации получается ОТРИЦАТЕЛЬНОЕ значение...
                        но почему тогда ПРОГГА не падает с выбрасыванием исключения, т к там происходит вычисление Ln при этом отриц. х?
                          нашел ошибку/опечатку!
                          здесь:
                          ExpandedWrap disabled
                            double F(double px)
                            {
                                return (8.0 / 5.0 * (log(px) + 1));
                            }


                          нужно подставлять ИСХОДНУЮ функцию...
                          и в этом случае ПРЕКРАСНО определяются ОБА корня! Ура...
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0790 ]   [ 19 queries used ]   [ Generated: 19.03.24, 07:04 GMT ]