简体   繁体   中英

C++ Finding root of the function

I have been asked to find the root of the below function

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

for two set of values

  • a=10 , b=2 and c=0
  • a=4.5 , b=2.8 , and c=1

But I have not been given the start and end values within which I need to find the root. How shall I proceed ?

Note: atan() represents inverse function of tan.

Code snippet:

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;
}

There's a bug in your implementation of your function.

atan(b*x - 1 / 2)

The term 1 / 2 does integer division and evaluates to 0 which is probably not what you want. In general, use double literals when doing arithmetic with double variables. The pow() function does take (double, int) as one of it's overloads so you're good there. It also has a (double, double) overload but if your exponent is in fact an integer then you don't want that.

Here's a simple implementation of the simplest root finding method -- the bisection method (I noticed afterwards that the OP used the bisection tag, perfect).

#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;
}

Output :

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)

The output will change with each run because this uses an RNG. Visually the outputs look right.

The code assumes the root is bounded by -1.0 and 1.0 which is true in your case. If you want it to be more general then you'll need to add logic for handling overflows and checking for nans. If the root isn't between -1.0 and 1.0 this will loop forever. Nonetheless, it solves the specific problem in this question and is a start for something more general.

Also note that your functions have multiple roots and the given code just finds a single root.

Edit: Cleaned up the code. Added entropy as an argument to BisectionMethod() so that it is reproducible which seems desirable if we're talking numerical methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM