2015-02-07 66 views
0

我一直在問,找到下面的功能功能的C++查找根

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

的根源有兩個設定值

  • a=10b=2c=0
  • a=4.5b=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

這是一個相當數學問題,我認爲它屬於另一個網站。但是,並非所有的查找算法都需要一個包含根的區間。所以,要麼嘗試其他算法,要麼挑選一些隨機值,如果公式給出不同的符號,則可以平分。 – Axel 2015-02-07 07:50:49

+0

不會。即使如果它似乎是一個數學問題,我被要求用C++實現。所以,我認爲它屬於這裏。你能幫我結構嗎? – tmgr 2015-02-07 07:51:56

+0

我不同意。你正在尋找一種算法,你根本沒有代碼。你必須先選擇算法,然後從這裏開始尋找:http://math.stackexchange.com/search?q=root+finding。如果您嘗試實現算法並陷入困境,那麼您可以回到這裏,發佈您的代碼並獲得答案。 – Axel 2015-02-07 07:59:30

回答

1

有你實現你的函數的一個bug。

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

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) 

輸出將每次運行時改變,因爲它使用一個RNG。在視覺上,輸出看起來是正確的

該代碼假定根以-1.0和1.0爲界,在您的情況下爲true。如果你希望它更一般,那麼你需要添加邏輯來處理溢出和檢查nans。如果根不在-1.0和1.0之間,這將永遠循環。儘管如此,它解決了這個問題中的具體問題,並且是更一般化的開始。

另請注意,您的函數有多個根,並且給定的代碼只能找到一個根。

編輯:清理了代碼。作爲BisectionMethod()的參數添加了entropy,以便重複性好,如果我們正在談論數值方法,這似乎是可取的。