在C中以数字方式求解常微分方程时的误差 - 错误:在'{'标记之前预期'=',',',';','asm'或'__attribute__'

时间:2017-02-02 07:35:50

标签: c numerical-methods differential-equations

编译C代码时出现以下错误。我正在使用Numerical Recipes 2nd ed。函数rk4()用于求解一阶微分方程。

我不是这个领域的专家。任何帮助将受到高度赞赏。

错误是:

first_order_DE_RK4_example1.c:75: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token

代码是:

#include "nrutil.h"
#include <stdio.h>
#include <math.h>

void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
    void (*derivs)(float, float [], float []));

void (*derivs)(float, float[], float[]);


int main()
{
  int n; float h; float x;
  float y[1];
  float dydx[1];

  n=1;
  h=0.2;
  x=0;
  y[0] = 1;
  dydx[0] = 5.0;

void rk4(float y[], float dydx[], int n, float x, float h, float yout[], 
     void (*derivs)(float, float [], float []));

  return 0;
}


void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
    void (*derivs)(float, float [], float []))
{
    int i;
    float xh,hh,h6,*dym,*dyt,*yt;

    dym=vector(1,n);
    dyt=vector(1,n);
    yt=vector(1,n);
    hh=h*0.5;
    h6=h/6.0;
    xh=x+hh;

    for (i=1;i<=n;i++) 
          { 
            yt[i]=y[i]+hh*dydx[i];
        (*derivs)(xh,yt,dyt);
          }

    for (i=1;i<=n;i++) 
          { yt[i]=y[i]+hh*dyt[i];
        (*derivs)(xh,yt,dym);
          }

    for (i=1;i<=n;i++) 
         {
        yt[i]=y[i]+h*dym[i];
        dym[i] += dyt[i];
     }

    (*derivs)(x+h,yt,dyt);

    for (i=1;i<=n;i++) 
          {
        yout[i]=y[i]+h6*(dydx[i]+dyt[i]+2.0*dym[i]);
          }

    free_vector(yt,1,n);
    free_vector(dyt,1,n);
    free_vector(dym,1,n);
}


void (*derivs)(float x, float y, float dydx)
 {
   float rhs;
   rhs = 1-x+4*y;
 }

2 个答案:

答案 0 :(得分:1)

您似乎无缘无故地使用函数指针,并将原型和声明与调用和定义混淆。

在顶部,这一变化:

void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
    void (*derivs)(float, float [], float []));

void (*derivs)(float, float[], float[]);
void rk4(float y[], float dydx[], int n, float x, float h, float yout[]);

void derivs(float, float[], float[]);

main中,这个:

void rk4(float y[], float dydx[], int n, float x, float h, float yout[], 
 void (*derivs)(float, float [], float []));
rk4(y, dydx, n, x, h, yout); // with some appropriate declared yout

rk4的定义中,

void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
    void (*derivs)(float, float [], float []))
void rk4(float y[], float dydx[], int n, float x, float h, float yout[])

拨打derivs中的rk4

(*derivs)(xh,yt,dyt);
derivs(xh, yt, dyt);

derivs的定义中,

void (*derivs)(float x, float y, float dydx)
void derivs(float x, float y[], float dydx[])

然后修复rhs

的计算

如果您发现自己将来编写sometype (*name而不打算使用函数指针,请停止。 =)

答案 1 :(得分:0)

在更正编译版本后,我运行diff以系统方式报告更改。这些变化及其原因是:

8c8
< void (*derivs)(float, float[], float[]);
---
> void myprime(float, float[], float[]);

为避免混淆,我将为参数和将填充该参数的用户定义函数使用不同的名称。

用户定义的派生函数只是一个普通的函数(过程,子程序,方法),函数指针声明仅限于实际将变量声明为函数指针的地方。

14a15
>   float yout[1];

添加缺少的变量声明。这将有助于程序编译,但不会运行,因为您混合了两个不同的索引范围。 float arr[N]的标准范围是0..N-1。 &{34;数字配方&#34;的vector辅助函数使用指针运算,以便float *arr=vector(L,H)的有效分配部分的索引范围是L..H。在您的当前代码中,您混合范围0..01..1,从而访问分配范围之外的内存。将所有内容切换为矢量和索引范围1..n

23,24c24
< void rk4(float y[], float dydx[], int n, float x, float h, float yout[], 
<      void (*derivs)(float, float [], float []));
---
>   rk4(y, dydx, n, x, h, yout, myprime);

调用函数看起来与声明该函数不同。在调用中,您只需使用参数的变量名称。

44,47c44,47
<           { 
<             yt[i]=y[i]+hh*dydx[i];
<         (*derivs)(xh,yt,dyt);
<           }
---
>     {
>         yt[i]=y[i]+hh*dydx[i];
>     }
>     derivs(xh,yt,dyt);

首先运行循环计算下一个状态向量,然后调用微分计算一次

将函数指针作为参数传递的想法是,然后使用它就像它是一个函数。无需添加任何解除引用等,C机制就是这样构建的。

这两点也适用于其他两个导数计算。顺便说一下,你错过了dydx中导数的计算。这个想法可能是这个值也在例程之外用于其他目的,所以传递它可以避免双重计算。

73c74
< void (*derivs)(float x, float y, float dydx)
---
> void myprime(float x, float y[], float dydx[])

使用名称更改实现用户定义的派生函数。

75,76c76
<    float rhs;
<    rhs = 1-x+4*y;
---
>    dydx[0] = 1-x+4*y[0];

ydydx的传递参数是向量,即使在标量情况下,也必须将它们视为具有适当解引用或元素寻址的向量。

您需要实现函数声明背后的意图。衍生计算的结果将存储在dydx