Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ЛБ3 / main

.cpp
Скачиваний:
0
Добавлен:
20.12.2024
Размер:
8.13 Кб
Скачать
#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;
}
Соседние файлы в папке ЛБ3
  • #
    20.12.202413.27 Кб0bisection.xlsx
  • #
    20.12.202411.75 Кб0combined.xlsx
  • #
    20.12.20248.13 Кб0main.cpp
  • #
    20.12.202412.96 Кб0newtons.xlsx
  • #
    20.12.20245.01 Mб0Звіт.docx