RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1525968
Accepted
Echobana
Echobana
Asked:2023-06-16 04:13:16 +0000 UTC2023-06-16 04:13:16 +0000 UTC 2023-06-16 04:13:16 +0000 UTC

将参数传递给函数指针

  • 772

以下代码允许您使用切线法求解方程:

#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++ 路径解决方案?

c++
  • 2 2 个回答
  • 58 Views

2 个回答

  • Voted
  1. Best Answer
    Stanislav Volodarskiy
    2023-06-16T04:38:07Z2023-06-16T04:38:07Z

    f是x的函数。k不是参数,而是实现细节。rhs也不是参数,而是方程y = f(x)中y的值。因此,您需要使f成为一个参数的函数,并从签名中排除其他所有内容。

    在现代 C++ 中,lambda 是将设置传递给函数的最佳方式。该功能solve必须制作模板。k通过闭包传递给f :

    #include <cmath>
    #include <iostream>
    
    template <typename Func>
    double solve(Func f, double y, double x_0 = 2.3, int n = 50) {
        double x = x_0;
        double dx = 1e-5;
    
        for (int i = 0; i < n; ++i) {
            x_0 = x;
            double df = (f(x + dx) - f(x)) / dx;
            x -= (f(x) - y) / df;
            if (x - x_0 < 1e-6) {
                return x;
            }
        }
        return x;
    }
    
    int main() {
        double k = 1.4;
        auto q_func = [k](double x) {
            return
                x *
                pow(1 - (k - 1) / (k + 1) * x * x, 1 / (k - 1)) *
                pow((k + 1) / 2, 1 / (k - 1))
            ;
        };
        std::cout << solve(q_func, 0.25) << std::endl;
    }
    

    如果您不喜欢 lambda 和样板代码,还有一种更传统的方法:创建一个接口并double operator()(double x)使用它的后代。你会得到这样的东西:

    #include <cmath>
    #include <iostream>
    
    class Func {
    public:
        virtual ~Func() {}
        virtual double operator()(double x) const = 0;
    };
    
    double solve(const Func &f, double y, double x_0 = 2.3, int n = 50) {
        double x = x_0;
        double dx = 1e-5;
    
        for (int i = 0; i < n; ++i) {
            x_0 = x;
            double df = (f(x + dx) - f(x)) / dx;
            x -= (f(x) - y) / df;
            if (x - x_0 < 1e-6) {
                return x;
            }
        }
        return x;
    }
    
    class QFunc : public Func {
    public:
        QFunc(double k) : k(k) {}
        virtual double operator()(double x) const override {
            return
                x *
                pow(1 - (k - 1) / (k + 1) * x * x, 1 / (k - 1)) *
                pow((k + 1) / 2, 1 / (k - 1))
            ;
        }
    private:
        double k;
    };
    
    int main() {
        QFunc q_func(1.4);
        std::cout << solve(q_func, 0.25) << std::endl;
    }
    

    PS就数学而言,df最好在循环内重新计算。否则,保证迭代收敛到根和收敛速度的标志不起作用。

    • 3
  2. Андрей Краевский
    2023-06-16T06:11:33Z2023-06-16T06:11:33Z

    有几种方法可以解决这个问题。您始终只能将仅采用一个参数 x 的函数传递给求解函数。如果你需要传递一个带有大量参数的函数,那么只需创建一个带有 1 x 参数的包装函数。

    #include <math.h>
    
    #include <iostream>
    
    double q_func(double x, double k, double rhs) {
      return x * pow(1 - (k - 1) / (k + 1) * x * x, 1 / (k - 1)) *
                 pow((k + 1) / 2, 1 / (k - 1)) -
             rhs;
    }
    
    double solve(double (*f)(double), double x_0 = 2.3, int n = 50) {
      double x = x_0;
      double dx = 1e-5;
      double df = (f(x + dx) - f(x)) / dx;
    
      for (int i = 0; i <= n; i++) {
        x_0 = x;
        x = x - f(x) / df;
        if (x - x_0 < 1e-6) {
          return x;
        }
      }
      return x;
    }
    
    int main() {
      auto wrapper = [](double x) { return q_func(x, 1.4, 0.25); };
      double x = solve(wrapper);
      std::cout << x << std::endl;
    
      return 0;
    }
    
    Можно сделать так чтобы solve принимала любые 
    

    如果 k、rhs 和其他参数在编译时已知,这将起作用。如果不是,那么将 lambda 转换为函数指针将不起作用。您可以添加一些概念来接受任何调用。这允许您在编译阶段传递参数未知的 lambda。

    #include <math.h>
    
    #include <concepts>
    #include <iostream>
    
    double q_func(double x, double k, double rhs) {
      return x * pow(1 - (k - 1) / (k + 1) * x * x, 1 / (k - 1)) *
                 pow((k + 1) / 2, 1 / (k - 1)) -
             rhs;
    }
    
    template <typename Func>
      requires std::invocable<Func, double> &&
               std::same_as<double, std::invoke_result_t<Func, double>>
    double solve(Func f, double x_0 = 2.3, int n = 50) {
      double x = x_0;
      double dx = 1e-5;
      double df = (f(x + dx) - f(x)) / dx;
    
      for (int i = 0; i <= n; i++) {
        x_0 = x;
        x = x - f(x) / df;
        if (x - x_0 < 1e-6) {
          return x;
        }
      }
      return x;
    }
    
    int main() {
      double k = 1.4;
      double rhs = 0.25;
    
      auto wrapper = [=](double x) { return q_func(x, k, rhs); };
    
      double x = solve(wrapper);
      std::cout << x << std::endl;
    
      auto wrapper2 =
          [](double first, double second) {
            return [=](double x) { return q_func(x, first, second); };
          };
    
      double x2 = solve(wrapper2(k, rhs));
      std::cout << x2 << std::endl;
    
      return 0;
    }
    

    您还可以使用模板将任意数量的参数传递给 solve 以及从 solve 传递给传递的函数。如果您使用这种方法,函数的参数应该放在最后,这将防止 n 和 x_0 成为默认参数。

    #include <math.h>
    
    #include <iostream>
    
    double q_func(double x, double k, double rhs) {
      return x * pow(1 - (k - 1) / (k + 1) * x * x, 1 / (k - 1)) *
                 pow((k + 1) / 2, 1 / (k - 1)) -
             rhs;
    }
    
    template <typename... Args>
    double solve(double x_0, int n, double (*f)(double, Args...),
                  Args... args) {
      double x = x_0;
      double dx = 1e-5;
      double df = (f(x + dx, args...) - f(x, args...)) / dx;
      for (int i = 0; i <= n; i++) {
        x_0 = x;
        x = x - f(x, args...) / df;
        if (x - x_0 < 1e-6) {
          return x;
        }
      }
      return x;
    }
    
    int main() {
      double k = 1.4;
      double rhs = 0.25;
    
      double x = solve(2.3, 50, q_func, k, rhs);
      std:: cout << x << std::endl;
      return 0;
    }
    
    • 1

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5