簡體   English   中英

C ++:牛頓拉夫森和重載函數

[英]C++: newton raphson and overloading functions

我編寫了一個牛頓拉弗森尋根算法的簡單實現,該算法將初始猜測init ,一元函數f和公差tol作為參數,如下所示:

bool newton_raphson(double& init,
                    double(*f)(double),
                    double tol){
    const int max_iter = 10000;
    double next_x, soln = init;
    int i = 0;

    while(++i < max_iter){
        next_x = soln - f(soln)/fp_x(f, soln);
        if(fabs(next_x - soln) < tol){
            init = next_x;
            return true;
        }
        soln = next_x;
    }
    return false;
}

double fp_x(double(*f)(double),
            double x){
    const double h = 0.000001;
    return (f(x + h) - f(x - h))/2.0/h;
}

我的問題是:盡管這對於一元函數非常合適,但我想更改實現,使其對具有多個參數但除了一個參數之外的所有參數都具有常量值的函數f 澄清一下:如果我有一個函數f(x)= 3x + 2,如下所示

double f(double x){
    return (3*x + 2);
}

然后我的實現工作。 但是,我也希望它適用於具有給定數量的參數的任何函數,但是只有第一個參數是變量。 所以,如果我有一個函數f(x,y)= 3x + 2y

double f(double x, double y){
    return (3*x + 2*y);
}

我想使用相同的函數找到f(x,2)或f(x,3)的根,依此類推,對於n個參數,而不僅僅是一兩個參數(請忽略我在函數中顯示的想法該示例是簡單的線性函數,這只是一個示例)。 有什么方法可以針對不同數量的參數實現該功能,還是我必須針對每種情況編寫一個實現?

謝謝,

NAX

注意

就像您現在可以說的那樣,這個問題並不是真正的關於牛頓拉普森的問題,但是如果我將其用作實際問題的示例,這將變得更加容易,它是針對不同數量參數的函數的單個實現。

UPDATE

下面的幾個答案使用std::bindstd::function解決問題,實際上比選擇的答案更好地解決了我的問題; 但是,它們是c ++ 11庫類/函數(不要誤會,這是我強烈敦促每個c ++程序員繼續學習的東西),在撰寫本文時,我遇到了一些問題使用它們; 使用g ++ 4.7(與c ++ 11兼容)的Eclipse Juno仍然無法識別std::function ,因此我決定繼續堅持下面的檢查結果,這也很好用。

我認為您正在要求可變函數:

可變參數函數(使用以省略號(...)結尾的參數列表聲明的函數)可以接受數量不同的不同類型的參數。 可變參數功能很靈活,但也很危險。 編譯器無法驗證對可變參數函數的給定調用是否傳遞了適當數量的參數或這些參數具有適當的類型。 因此,對傳遞不適當參數的可變參數函數的運行時調用會產生未定義的行為。 可以利用這種未定義的行為來運行任意代碼。 從這里:

https://www.securecoding.cert.org/confluence/display/cplusplus/DCL31-CPP.+Do+not+define+variadic+functions

但是,如上所述,它們存在許多問題。

最值得注意的是,它僅在編譯時有效!

但是,如果您對實現一個對象感興趣,那么這里有一個很好的示例文章:

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=138

更新:

IMO,我認為最好是定義帶有結構或對象參數的函數(即通用函數對象),並顯式地編寫對這些參數起作用的函數。

另一個選擇是進行一些編譯時反射 -這很有用,但在這樣的示例中這樣做太麻煩了。 另外,C ++中的“反射”不是“真實的”反射,而是它的一種糟糕且不完整的實現。

對於您要在此處執行的操作,您正在尋找的是std::bind (或者,如果要處理C ++ 03編譯器,則是std::bind1ststd::bnd2nd )。

這些使您可以將值“綁定”到其他參數,從而為您提供僅需要單個參數的函數(技術上為函數對象)。

您理想的情況是:

double f(double x, double y) { 
     return 3*x + 2*y;
}

double init = 1.0;

newton_raphson(init, std::bind2nd(f, 3), 1e-4);

不幸的是,在實際使用中,它並不是那么簡單-要使用std::bind2nd ,就不能使用實際的函數。 您需要改用功能對象,並且必須從std::binary_function派生。

std::bind相當靈活,因此幾乎可以肯定要使用它(如果可能的話)。

您可以使用std::bindstd::function 類型std::function<double(double)>表示一個接受double並返回double的函數。 同樣, std::function<double(int,int)>適用於采用2個整數的函數,並返回一個double。

#include <functional>

bool newton_raphson(double& init,
                    std::function<double(double)>& f,
                    double tol){
    const int max_iter = 10000;
    double next_x, soln = init;
    int i = 0;

    while(++i < max_iter){
        next_x = soln - f(soln)/fp_x(f, soln);
        if(fabs(next_x - soln) < tol){
            init = next_x;
            return true;
        }
        soln = next_x;
    }
    return false;
}

double myfunction(double x, double y){
    return (3*x + 2*y);
}
double fp_x(std::function<double(double)> f, double x) {
    ...
}
...
double d = 1.0;
// Here we set y=2.5 and we tell bind that 1st parameter is unbounded
// If we wanted to switch and set x=2.5 and let y be unbounded, then
// we would use  (&myfunction, 2.5, std::placeholders::_1)
newton_raphson(d, std::bind(&myfunction, std::placeholders::_1, 2.5) , 1e-6);
...

我用您的問題來強迫自己學習C ++ 11可變參數模板,這是一個有效的示例。

template< typename... Ts >
double f( Ts... Vs ) {
    double array[] = { Vs... };
    int numArg = sizeof...( Vs );
    switch (numArg) {
    case 1:
        return 3 * array[0] + 2;
    case 2:
        return 3 * array[0] + 2 * array[1];
    case 3:
        return 3 * array[0] + 2 * array[1] + 1 * array[3];
    ....
    default:
        return 0.0;
    }
}

template< typename... Ts >
double newton_raphson( double &init, double tol,
                       double (*func) ( Ts... Vs ), Ts... Vs ) {
    return func( Vs... );
}

你可以這樣稱呼它

newton_raphson( &init, 1.0, f, 1.0, 2.0, 3.0, 4.0, 5.0 );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM