如何在C语言中使用Trapezoidal Rule对带参数的sin(a*x)*sin(b*x)积分
解决方案
你需要给作为回调的被积函数传递额外自定义参数,C语言中常见的实现方式有以下几种:
方法1:修改积分函数,新增通用上下文参数(最推荐,无副作用,线程安全)
调整trapzd的函数签名,增加一个void*类型的参数用来传递自定义数据,同时修改回调函数的类型,让它可以接收这个上下文参数,这是C语言回调传参的标准实现方案。
修改后的完整代码如下:
#include <stdio.h> #include <math.h> // 定义用来传递myfunc额外参数的结构体 typedef struct { float aa; float bb; } FuncParams; // 被积函数签名修改为接收x和上下文参数 float myfunc(float x, void* params) { FuncParams* p = (FuncParams*)params; return sin(p->aa * x) * sin(p->bb * x); } // 积分函数修改:新增上下文参数,回调函数类型同步修改 float trapzd(float (*func)(float, void*), void* func_params, float a, float b, int n) { float x, tnm, sum, del; static float s; int it, j; if (n == 1) { return (s = 0.5 * (b - a) * (func(a, func_params) + func(b, func_params))); } else { for (it = 1, j = 1; j < n-1; j++) it <<= 1; tnm = it; del = (b - a) / tnm; x = a + 0.5 * del; for (sum = 0.0, j = 1; j <= it; j++, x += del) { sum += func(x, func_params); } s = 0.5 * (s + (b - a) * sum / tnm); return s; } } int main() { // 构造要传入的a、b参数 FuncParams params = {.aa = 0, .bb = 5}; // 调用积分函数时传入参数结构体指针 printf("%f\n", 2 * trapzd(myfunc, ¶ms, 0, 1, 5)); return 0; }
方法2:使用全局变量存储a、b(仅适合临时测试用,不推荐)
如果不想修改原有trapzd的函数签名,可以把aa和bb定义为全局变量,myfunc直接读取全局变量的值。
示例代码如下:
#include <stdio.h> #include <math.h> // 全局变量存储参数 float g_aa, g_bb; float myfunc(float x) { return sin(g_aa * x) * sin(g_bb * x); } float trapzd(float (*func)(float), float a, float b, int n) { float x, tnm, sum, del; static float s; int it, j; if (n == 1) { return (s = 0.5 * (b - a) * (func(a) + func(b))); } else { for (it = 1, j = 1; j < n-1; j++) it <<= 1; tnm = it; del = (b - a) / tnm; x = a + 0.5 * del; for (sum = 0.0, j = 1; j <= it; j++, x += del) { sum += func(x); } s = 0.5 * (s + (b - a) * sum / tnm); return s; } } int main() { // 调用前先给全局变量赋值 g_aa = 0; g_bb = 5; printf("%f\n", 2 * trapzd(myfunc, 0, 1, 5)); return 0; }
该方案缺点明显:非线程安全,同时多次调用积分函数时会互相干扰,代码可维护性差。
原有代码笔误修正
你提供的示例代码还有几处语法错误需要注意:
- 积分函数中调用的
h(a)、h(b)是错误的,应该调用你传入的回调函数func - 移位运算符
<<=、加法赋值运算符+=中间不能有空格 trapzd函数的else块结束后缺少右大括号- 直接在参数列表里写
myfunc(float x, 0, 5)不符合C语法,函数名作为参数传递时只需要写函数名本身,不需要带参数列表
内容的提问来源于stack exchange,提问作者F.Mark
相关产品推荐
相关产品推荐

