MLoop 2

Задача. Используйте метод хорд для того, чтобы отыскать с точностью [latex]\varepsilon[/latex] все действительные корни уравнения  [latex]\frac{x}{2 \cdot sin x +1}=tan(ln(x^2+1))[/latex].  Для подготовки необходимых графиков воспользуйтесь этим ресурсом.

Тесты(найдено с помощью математической системы WolframAlpha):

[latex]A[/latex] [latex]B[/latex] [latex]x\approx[/latex]
-20 20  -11.6945378230838209122818536587051434153…


-1.25741503276862309237205903178504130394…

0


0.547316310185252929580383582338832450320…

10.9948442206261587135425985750810372810…

Код программы

 

Алгоритм

Для начала запишем данное нам уравнение в виде функции [latex]y=f(x)[/latex] и построим ее график:

[latex]y=\frac{x}{2 \cdot sin x +1}-tan(ln(x^2+1))[/latex]

 

save (4)

Задача о нахождении приближённых значений действительных корней уравнения [latex]f(x)=0[/latex] предусматривает предварительное отделение корня, то есть установление интервала, в котором других корней данного уравнения нет.

Метод хорд предусматривает замену функции на интервале на секущую, и поиск ее пересечения с осью [latex]OX[/latex]. На заданном интервале [latex][a,b][/latex] с точностью [latex]\varepsilon[/latex] корень будет вычисляться согласно итерационному выражению, которое имеет вид:

[latex]x_{i+1}=x_{i-1}-\frac{f(x_{i-1}) \cdot (x_{i}-x_{i-1})}{f(x_{i})-f(x_{i-1}) ) }[/latex]

Данный метод имеет свои недостатки. В первую очередь видно, что он не учитывает возможную разрывность функции, вследствие чего могут возникать ложные корни, или пропадать имеющиеся. Как же выяснить, есть ли корень на данном отрезке? Рассмотрим и проанализируем случаи, в которых метод хорд может выдать ошибочный результат. Возможны следующие варианты:

1. В точке, где находится предполагаемый корень, имеется разрыв второго рода. Здесь метод хорд обнаруживает перемену знака и начинает сужать отрезок. Однако расстояние между крайними точками  отрезка не уменьшается, а увеличивается. А именно увеличивается проекция отрезка на ось [latex]OY[/latex]. И чем ближе мы находимся к точке разрыва, тем она больше, а в самой точке стремится к бесконечности. В качестве примера приведем функцию [latex]\frac{(x-5)^2}{x-4}[/latex], имеющую разрыв второго рода в точке [latex]x=4[/latex].
save

2. Аналогичный случай — точка разрыва первого рода, где наша хорда стремится к некоторой константе — величине разрыва. Пример — функция [latex]\frac{\sin x\cdot(x-2.5)}{\left | x-2,5 \right |}[/latex], имеющая разрыв первого рода в точке [latex]x=2,5[/latex].
save (1)

3. Функция не является разрывной и даже имеет корень, однако в точке корня производная стремится к бесконечности. Например, функция [latex]\sqrt[3]{x-1,2}[/latex], имеющая корень в точке [latex]x=1,2[/latex]. Для функций подобного рода длина проекции отрезка на ось [latex]OY[/latex] будет очень медленно меняться, вследствие чего для разумного числа итераций она будет превосходить заранее выбранную точность [latex]\varepsilon[/latex].

save (2)

4. Функция равна нулю или очень близка к нулю на некотором интервале(например, функция [latex]y=rect(x-1,5)\cdot(x-1)\cdot(x-2)^2[/latex]). Здесь метод хорд найдет пересечение с осью [latex]OX[/latex]  в интервале, где находятся корни(одна из сторон отрезка будет корнем), но все последующие итерации будут выдавать эту же точку. Поэтому хорда не будет уменьшаться, и даже этот один корень не будет найден(если будет использоваться стандартная [latex]\delta[/latex]-оценка точности по оси [latex]OX[/latex]).

save (3)

5. Функция вида [latex]y=x^{2k}[/latex] или ей подобная, например, [latex]y=1+\sin x[/latex], к которой метод хорд вообще не применим, так как нарушается начальное условие применимости этого метода. Здесь нужно ввести дополнительную проверку. Изменим значение функции на небольшую константу — нашу точность [latex]\varepsilon[/latex] и повторим процедуру поиска корней. В результате мы получим [latex]2k[/latex] корней, каждую пару из которых мы можем считать краями интервала, в котором лежит настоящий корень.

save (6)

К счастью, в данной нам функции присутствует только один из этих случаев, а именно разрыв второго рода. Аналитически рассмотрев нашу функцию, мы обнаружили, что корни следует искать в окрестности точек[latex]\sqrt{e^{\frac{\pi}{2}+\pi \cdot k}-1}[/latex] с отклонением [latex]\pm\pi[/latex]. В корнях функции ее производная быстро растет с ростом [latex]k[/latex].

Критерием отбрасывания кандидата на корень будет рост длины хорды при сужении интервала. Критерием останова будет сужение интервала до заданной точности [latex]\delta[/latex].
Код программы

3 thoughts on “MLoop 2

  1. Молодец, проделана большая работа и получен хороший результат.
    И как с каждой большой работой, есть о чём поговорить.

    По оформлению.
    Пожалуйста, задавайте стандартные функции в latex правильно: \sin x, а не sin x и т.п.

    По коду.
    — Если нужна бесконечность типа double, то резонно выбрать DBL_MAX. Задавая своё число «с потолка» Вы рискуете.
    — Отступы. Я писал Вам подробный комментарий по поводу GNU-style, который Вы выбрали. Пожалуйста, придерживайтесь стандартов. Что касается дополнительного пробела для демонстрации зависимости по данным, то либо Вы к ней относитесь не очень строго, либо я не все Ваши идеи понял:
    — что означает дополнительный сдвиг в строке 64?
    — почему 46-я сдвинута на два пробела, а не один?
    Предлагаю решить так. В процессе программирования Вы используете любые личные наработки и оригинальный стиль. Но перед публикацией делаете свою работу понятной читателю. Т.е. оформляете код в одном из существующих стилей. В этом случае Вы не потеряете своей оригинальности, но и приобретёте навыки социализации, необходимые в общении с другими программистами. Кстати, я пользуюсь системой автоматической расстановки отступов, чтобы читать Ваш код. Может и Вам она пригодится.
    Согласны?

    По содержанию.
    Вы пишите «В общем случае функция имеет ряд промежутков, на которых это условие не выполняется». Что означает «в общем случае»? У нас одна конкретная функция, мы ничего не обобщаем.
    Дальше. Нам не нужно, чтобы функция была монотонной везде. Нужно только, чтобы существовала окрестность корня в которой функция была монотонна.

    По тестам.
    — Тесты, это то, что ДОЛЖНА выдать программа, а не то, что она выдаёт. Вы пишите, что точка 0 является корнем функции при точности 10-6, но при точности 10-12 она уже не корень. Объясните, почему?
    — Правильно было бы найти корни с помощью какой-либо математической системы:
    x~ -11.6945378230838209122818536587051434153…
    x~ -1.25741503276862309237205903178504130394…
    x = 0
    x~ 0.547316310185252929580383582338832450320…
    x~ 10.9948442206261587135425985750810372810…
    и сделать их эталонными тестами для проверки программы.

    Что ожидалось?
    Как видите количество корней бесконечно, и из-за логарифма функция не является периодической. Как же численно найти «все». Понятное дело — никак! Значит стоит «научить» программу находить отделять интервал очередного (то положительного, то отрицательного) корня и находить его без остановки программы. Т.е. она должна выдавать последовательные корни без остановки.
    Вы спросите — а можно оставить как есть? Можно. Только поправьте предыдущие замечания.