численные методы — C ++ Нахождение корня функции

Меня попросили найти корень функции ниже

sin((a*x / (1 + pow(x, 2))) + 1) * atan(b*x - 1 / 2) + exp(-c*x) * atan(x)

для двух наборов значений

  • a=10, b=2 а также c=0
  • a=4.5, b=2.8, а также c=1

Но мне не дали Начните а также конец значения, в пределах которых мне нужно найти корень. Как мне поступить?

Примечание: atan () представляет обратную функцию tan.

Фрагмент кода:

double f(double x, double a, double b, double c)
{
return sin((a*x / (1 + pow(x, 2))) + 1) * atan(b*x - 1 / 2) + exp(-c*x) * atan(x);
}

double RootFinder(double f(double, double, double, double), double a, double b, double c, double left, double right, double precision)
{
double f_left = f(left, a, b, c), now = left + precision, f_right = f(now, a, b, c);
while (f_left * f_right > 0 && now < right)
{
f_left = f_right;
now += precision;
f_right = now;
}
return now - precision / 2;
}

0

Решение

В вашей реализации вашей функции есть ошибка.

atan(b*x - 1 / 2)

Семестр 1 / 2 делает целочисленное деление и оценивает в 0, что, вероятно, не то, что вы хотите. В общем, используйте двойные литералы при выполнении арифметики с двойными переменными. pow() функция берет (double, int) как одна из перегрузок, так что вы хорошо там. Он также имеет (double, double) перегрузка, но если ваш показатель на самом деле является целым числом, то вы этого не хотите.

Вот простая реализация простейшего метода поиска корня — метода деления пополам (впоследствии я заметил, что OP использовал тег деления пополам, совершенный).

#include <iostream>
#include <cmath>
#include <random>

double f(const double x, const double a, const double b, const double c)
{
return sin((a*x / (1.0 + pow(x, 2))) + 1.0) * atan(b*x - 1.0 / 2.0) + exp(-c*x) * atan(x);
}

double BisectionMethod(
double f(double, double, double, double),
const double a, const double b, const double c,
const std::random_device::result_type entropy)
{
std::mt19937 gen(entropy);
static const auto lower_bound = -1.0;
static const auto upper_bound =  1.0;
std::uniform_real_distribution<> dis(lower_bound, upper_bound);

auto pos_pt = dis(gen);
auto neg_pt = dis(gen);

while (f(pos_pt, a, b, c) < 0.0)
pos_pt = dis(gen);

while (f(neg_pt, a, b, c) > 0.0)
neg_pt = dis(gen);

static const auto about_zero_mag = 1E-8;
for (;;)
{
const auto mid_pt = (pos_pt + neg_pt)/2.0;
const auto f_mid_pt = f(mid_pt, a, b, c);
if (fabs(f_mid_pt)  < about_zero_mag)
return mid_pt;

if (f_mid_pt >= 0.0)
pos_pt = mid_pt;
else
neg_pt = mid_pt;
}
}

int main()
{
double a, b, c;
std::random_device rd;
static const auto entropy = rd();

a =10, b = 2.0, c = 0.0;
const auto root1 = BisectionMethod(f, a, b, c, entropy);
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
std::cout << "Found root: (" << root1 << ", " << f(root1, a, b, c) << ")" << std::endl;

a =4.5, b = 2.8, c = 1.0;
const auto root2 = BisectionMethod(f, a, b, c, entropy);
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
std::cout << "Found root: (" << root2 << ", " << f(root2, a, b, c) << ")" << std::endl;
}

Выход:

g++ -O3 -std=c++11 -Wall -Wextra -pedantic main.cpp -o root && ./root
a = 10, b = 2, c = 0
Found root: (0.143042, -2.12425e-09)
a = 4.5, b = 2.8, c = 1
Found root: (0.136172, 5.81247e-09)

Выходные данные будут меняться с каждым прогоном, поскольку при этом используется ГСЧ. Визуально результаты выглядят правильно.

Код предполагает, что корень ограничен -1.0 и 1.0, что верно в вашем случае. Если вы хотите, чтобы оно было более общим, вам нужно добавить логику для обработки переполнений и проверки на nans. Если корень не между -1.0 и 1.0, это будет цикл навсегда. Тем не менее, он решает конкретную проблему в этом вопросе и является началом чего-то более общего.

Также обратите внимание, что ваши функции имеют несколько корней, и данный код просто находит один корень.

Редактировать: Убрал код. добавленной entropy в качестве аргумента BisectionMethod() так что это воспроизводимо, что кажется желательным, если мы говорим о численных методах.

1

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector