
Добавил:
webxxcom
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:ЛБ3 / main
.cpp#include <vector>
#include <iostream>
#define f(x) value_of_function(x)
//Parameters of cubic parabola
constexpr double a = 1.;
constexpr double b = 1;
constexpr double c = -4;
constexpr double d = -4;
constexpr double epsilon = 0.001;
//Returns value of function with the specified input
static double value_of_function(const double x)
{
return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}
//Find the value of first derivative of a function
static double value_of_first_derivative(const double x)
{
return 3 * a * pow(x, 2) + 2 * b * x + c;
}
//Find second derivative value of a function
static double value_of_second_derivative(const double x)
{
return 6 * a * x + 2 * b;
}
//Find the critical point of cubic parabola
static std::vector<double> find_the_critical_points()
{
std::vector<double> crit_points;
double temp_a = a * 3.;
double temp_b = b * 2.;
//discriminant
double D = temp_b * temp_b - 4. * temp_a * c;
if (D > 0)
{
//find the roots
double x1 = (-temp_b + sqrt(D)) / (2. * temp_a);
double x2 = (-temp_b - sqrt(D)) / (2. * temp_a);
//return roots in ascending order
if (x1 > x2)
std::swap(x1, x2);
crit_points.insert(crit_points.end(), { x1,x2 });
}
else if (D == 0)
crit_points.emplace_back(-temp_b / (2. * temp_a));
else
{
std::cout << "\nThe given function has no critical points.\n" <<
"The separation of the roots CAN NOT be performed.\n";
exit(EXIT_FAILURE);
}
std::cout << "The critical points of the function are at: ";
for (size_t i = 0; i < crit_points.size(); ++i)
std::cout << "x" << i+1 << ": " << crit_points[i] << ", ";
std::cout << std::endl << std::endl;
return crit_points;
}
//Specifies whether function has a root at the interval
static bool has_root_at_the_interval(const double left, const double right)
{
double left_value = value_of_function(left);
double right_value = value_of_function(right);
return left_value * right_value < 0;
}
//Finds the correct intervals where function has different signs
static std::vector<double> find_intervals()
{
//vector of function critical points
const std::vector<double> crit_points = find_the_critical_points();
//points of intervals
std::vector<double> points;
//value to increase/decrease points' value
double dx = 0.1;
double right_limit;
double left_limit;
const int MAX_ITERATIONS = 3000;
for (size_t i = 0; i < crit_points.size(); i++)
{
//set the right limit as a difference between current critical point and dx
right_limit = crit_points[i] - dx;
//set the left limit with smaller value as right limit
left_limit = right_limit - dx;
//iterate while the function values in current points don't have different signs
int j = 0;
while (j <= MAX_ITERATIONS)
{
if (i > 0)
dx = std::abs(left_limit - crit_points[i - 1]) / 2;
left_limit -= dx;
//found two points with different function signs
if (f(left_limit) * f(right_limit) < 0)
{
points.insert(points.end(), { left_limit, right_limit });
break;
}
++j;
//the left limit value exceeded the left critical point so no root in here.
if (i > 0 && left_limit < crit_points[i - 1])
break;
}
}
//set the rightmost interval(the left limit is bigger than the last critical point)
left_limit = crit_points.back() + dx;
right_limit = left_limit + dx;
int j = 0;
while (j <= MAX_ITERATIONS)
{
++right_limit;
if (f(left_limit) * f(right_limit) < 0)
{
points.insert(points.end(), { left_limit, right_limit });
break;
}
++j;
}
points[0] -= 1; points[points.size() - 1] += 1;
return points;
}
static void root_separation()
{
std::vector<double> intervals = find_intervals();
for (size_t i = 0; i < intervals.size() - 1; i += 2)
std::cout << "Function has a root at the interval: [" << intervals[i] << ", " << intervals[i + 1] << "]\n";
std::cout << std::endl << "In total, the function has " << intervals.size() / 2 << " roots\n";
}
//Tells the results of the given method
static void result_of_method(std::string const& name, std::vector<double> roots, int iterations)
{
std::cout << "The " << name << " method" << " required " << iterations <<
" number of iterations to find all the roots\n" <<
"The approximate roots are: \n";
for (size_t i = 0; i < roots.size(); i++)
std::cout << "x" << i + 1 << " = " << roots[i] << std::endl;
std::cout << std::endl;
}
//Bisection method to solve cubic equation
static void bisection_method()
{
std::vector<double> roots;
std::vector<double> intervals = find_intervals();
int k = 0;
for (size_t i = 0; i < intervals.size(); i += 2)
{
double ak = intervals[i];
double bk = intervals[i + 1];
double ck;
//actually this step is uncessary because in 'find_intervals' we actually perform this check
if (!has_root_at_the_interval(ak, bk))
continue;
while (std::abs(ak - bk) >= 2 * epsilon)
{
ck = (ak + bk) / 2.;
if (f(ak) * f(ck) < 0)
bk = ck;
else if (f(bk) * f(ck) < 0)
ak = ck;
++k;
}
ck = (ak + bk) / 2.;
roots.emplace_back(ck);
}
result_of_method("Bisection", roots, k);
}
//Bisection method to solve cubic equation
static void newtons_method()
{
std::vector<double> roots;
std::vector<double> intervals = find_intervals();
int k = 0;
for (size_t i = 0; i < intervals.size(); i += 2)
{
//actually this step is uncessary because in 'find_intervals' we actually perform this check
if (!has_root_at_the_interval(intervals[i], intervals[i + 1]))
continue;
double x0;
double x = (intervals[i] + intervals[i + 1]) / 2;
if (value_of_first_derivative(x) * value_of_second_derivative(x) < 0)
x = intervals[i];
else
x = intervals[i + 1];
do
{
x0 = x;
x = x - (f(x) / value_of_first_derivative(x));
++k;
} while (std::abs(x0 - x) >= epsilon);
roots.emplace_back(x);
}
result_of_method("Newton's", roots, k);
}
//Combined method to solve cubic equation
static void combined_method()
{
std::vector<double> roots;
std::vector<double> intervals = find_intervals();
int k = 0;
for (size_t i = 0; i < intervals.size(); i += 2)
{
//actually this step is uncessary because in 'find_intervals' we actually perform this check
if (!has_root_at_the_interval(intervals[i], intervals[i + 1]))
continue;
double a_k = (intervals[i] + intervals[i + 1]) / 2;
double b_k;
if (value_of_first_derivative(a_k) * value_of_second_derivative(a_k) < 0)
{
a_k = intervals[i];
b_k = intervals[i + 1];
}
else
{
b_k = intervals[i];
a_k = intervals[i + 1];
}
while (std::abs(a_k - b_k) > 2 * epsilon)
{
b_k = b_k - ( f(b_k) * (a_k - b_k) ) / ( f(a_k) - f(b_k) );
a_k = a_k - (f(a_k) / value_of_first_derivative(a_k));
++k;
}
double root = (a_k + b_k) / 2;
roots.emplace_back(root);
}
result_of_method("combined", roots, k);
}
int main()
{
std::cout << value_of_function(INFINITY);
return 1;
}