以下代码允许您使用切线法求解方程:
#include <iostream>
double q_func(double x, double k, double y)
{
return x * pow(1 - (k-1)/(k+1) * x * x, 1/(k-1)) * pow((k+1)/2, 1/(k-1)) - y;
}
double solve(double (*f)(double, double, double), double k, double y, double x_0=2.3, int n=50)
{
double x = x_0;
double dx = 1e-5;
double df = (f(x+dx, k, y)-f(x, k, y))/dx;
for (int i=0; i<=n;i++){
x_0 = x;
x -= f(x, k, y) / df;
if (abs(x - x_0) < 1e-6)
return x;
}
return x;
}
int main() {
double x = solve(q_func, 1.4, 0.25);
std::cout << x << std::endl;
return 0;
}
该函数q_func
有 3 个参数,现在,为了求解方程 (find x
),我将solve
两个额外的参数k
和传递给函数y
。
事实证明,在为函数添加参数时,q_func
我需要额外重写solve
. 在这种情况下,具有两个参数的方程无法再求解,需要保存旧签名,导致代码重复。有什么办法可以避免这种情况吗?
主要是想到传递vector
或map
第二个参数,但也许有更多的 C++ 路径解决方案?
f是x的函数。k不是参数,而是实现细节。rhs也不是参数,而是方程y = f(x)中y的值。因此,您需要使f成为一个参数的函数,并从签名中排除其他所有内容。
在现代 C++ 中,lambda 是将设置传递给函数的最佳方式。该功能
solve
必须制作模板。k通过闭包传递给f :如果您不喜欢 lambda 和样板代码,还有一种更传统的方法:创建一个接口并
double operator()(double x)
使用它的后代。你会得到这样的东西:PS就数学而言,df最好在循环内重新计算。否则,保证迭代收敛到根和收敛速度的标志不起作用。
有几种方法可以解决这个问题。您始终只能将仅采用一个参数 x 的函数传递给求解函数。如果你需要传递一个带有大量参数的函数,那么只需创建一个带有 1 x 参数的包装函数。
如果 k、rhs 和其他参数在编译时已知,这将起作用。如果不是,那么将 lambda 转换为函数指针将不起作用。您可以添加一些概念来接受任何调用。这允许您在编译阶段传递参数未知的 lambda。
您还可以使用模板将任意数量的参数传递给 solve 以及从 solve 传递给传递的函数。如果您使用这种方法,函数的参数应该放在最后,这将防止 n 和 x_0 成为默认参数。