【问题标题】:Nested function pointers or function composition嵌套函数指针或函数组合
【发布时间】:2021-07-02 08:51:47
【问题描述】:

我正在研究微积分运算的 C 实现(例如导数、积分等)。例如,这是我的 derivative 函数的模板定义:

double derivative(double (*f)(double), double x);

假设我想计算 exp 在 1 处的导数,那么调用将是:derivative(exp, 1);

相当基本的东西。现在我的问题是,我将如何(如果可能的话)将合成传递给我的 derivative 函数?我尝试通过 exp(cos) 得到了我

error: passing 'double (double)' to parameter of incompatible type 'double'.

我该怎么做?有没有可能?

【问题讨论】:

  • 我不明白这个问题。将cos 函数传递给exp 函数有什么意义?你能举一个你想要解决的实际方程的例子吗?
  • @Lundin 我想做的是计算任何组合的导数(exp(cos(x)) 只是一个例子,ln(sqrt(x)) 是另一个例子)
  • 在这种情况下,正确的解决方案是依次调用函数。使用泛型编程来实现这样的方程可能没有多大意义。
  • 人们可能会认为 C 是错误的语言?可行的并不总是可行的。

标签: c math function-pointers function-composition


【解决方案1】:

我想你是在问这个:

double composition(double x) {
   return exp(cos(x));
}

derivative(composition, 1);

许多语言允许您执行以下操作,但 C 没有匿名函数:

derivative(x => exp(cos(x)), 1);

【讨论】:

    【解决方案2】:

    如果您想要对组合进行某种运行时控制,您可以编写一个函数,将函数指针数组评估为组合:

    // calls functions in reverse order
    double compose(size_t n, double (* const fc[])(double), double x)
    {
        while (n--)
        {
            x = fc[n](x);
        }
        return x;
    }
    

    这可以从您的衍生函数的另一个版本中调用:

    double derivative_composed(size_t n, double (* const fc[])(double), double x)
    {
        // Example implementation for illustrative purpose only.
        double fx, fxh, h;
        h = x / 1e10;
        if (h == 0)
        {
            h = 1e-10;
        }
        fx = compose(n, fc, x);
        fxh = compose(n, fc, x + h);
        return (fxh - fx) / h;
    }
    

    为避免重复代码,您原来的 derivative 函数可以更改为使用单个函数调用 derivative_composed 的包装器:

    double derivative(double (* const f), double x)
    {
        return derivative_composed(1, &f, x);
    }
    

    示例用法:

    int main(void)
    {
        double (* const fc[2])(double) = { exp, cos };
        double x = 1.0;
        double xprime = derivative_composed(2, fc, x);
        printf("x = %f, xprime = %f\n", x, xprime);
    }
    

    输出:

    x = 1.000000, xprime = -1.444407
    

    【讨论】:

    • 是的,我想这是做我想做的事情的唯一“实用”方法。感谢您的回答和代码示例!
    【解决方案3】:

    C 没有任何函数组合的操作。要计算exp∘cos的导数,可以定义一个函数expcos

    double expcos(double x) 
    {
        return exp(cos(x));
    }
    

    并取其导数。

    对于更通用的解决方案,您可以修改派生例程以同时使用函数指针和 const void * 来转发到函数。该函数将const void * 作为参数,将其转换为指向该函数特定类型的const 结构的指针,并从该结构中获取数据。然后可以使用compose 函数来实现函数组合,该函数使用包含两个函数指针的结构。但是,这意味着您需要对接受但忽略 const void * 的普通函数(如 expcos)使用代理例程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      • 2010-09-07
      • 2010-11-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多