从循环中删除if语句

时间:2017-11-07 23:55:58

标签: c loops optimization

我在C中有以下循环,我试图从中删除if语句,以便每次迭代都不会检查它们。然而,我正在努力做到这一点。有没有人对如何把它们拿出来有任何建议?

for(ix=0;ix<Nx;ix++) {
  for(iy=0;iy<Ny;iy++) {
    if (ix==0) {
      pudx = (u[1][iy] + u[Nx-1][iy] - 2.0*u[0][iy])*(calc1);   
    } else if (ix==Nx-1) {
      pudx = (u[0][iy] + u[Nx-2][iy] - 2.0*u[Nx-1][iy])*(calc1);  
    } else {
      pudx = (u[ix+1][iy] + u[ix-1][iy] - 2.0*u[ix][iy])*(calc1);
    }
    if (iy==0) {
      pudy = (u[ix][1] + u[ix][Ny-1] - 2.0*u[ix][0])*(calc2);    
    } else if (iy==Ny-1) {
      pudy = (u[ix][0] + u[ix][Ny-2] - 2.0*u[ix][Ny-1])*(calc2);   
    } else {
      pudy = (u[ix][iy+1] + u[ix][iy-1] - 2.0*u[ix][iy])*(calc2);
    }
    u_new[ix][iy] = 2.0*u[ix][iy] - u_old[ix][iy] + calc*(pudx+pudy);
  }
}

3 个答案:

答案 0 :(得分:1)

for(ix=0;ix<Nx;ix++) {
    for(iy=0;iy<Ny;iy++) {

        pudx = (u[(ix+1)%Nx][iy] + u[(Nx+ix-1)%Nx][iy] - 2.0*u[ix][iy])*(calc1); 
        pudy = (u[ix][(iy+1)%Ny] + u[ix][(Ny+iy-1)%Ny] - 2.0*u[ix][iy])*(calc2);

        u_new[ix][iy] = 2.0*u[ix][iy] - u_old[ix][iy] + calc*(pudx+pudy);
    }
}

这不是优化。它只是删除你要求的if条件。

答案 1 :(得分:1)

这是一个简单的解决方案:从循环中取出if内容并使其更明确。它更长,但它可以节省您可能耗时的分支和模/分计算。我使用预处理器宏来使事情更清晰,并减少复制粘贴错误的可能性。宏应该本地化为相关代码,否则calc1u_old之类的变量将导致编译错误。基本上,您可以使用以下代码替换有问题的循环:

#define PUDX0 ((u[1][iy] + u[Nx-1][iy] - 2.0*u[0][iy])*(calc1))
#define PUDX ((u[ix+1][iy] + u[ix-1][iy] - 2.0*u[ix][iy])*(calc1))
#define PUDXN ((u[0][iy] + u[Nx-2][iy] - 2.0*u[Nx-1][iy])*(calc1))

#define PUDY0 ((u[ix][1] + u[ix][Ny-1] - 2.0*u[ix][0])*(calc2))
#define PUDY ((u[ix][iy+1] + u[ix][iy-1] - 2.0*u[ix][iy])*(calc2))
#define PUDYN ((u[ix][0] + u[ix][Ny-2] - 2.0*u[ix][Ny-1])*(calc2))

#define UNEW(x, y, pudx, pudy) u_new[x][y] = 2.0*u[x][y] - u_old[x][y] + calc*(pudx+pudy)

// ix = 0, iy = [0..Ny-1]
UNEW(0, 0, PUDX0, PUDY0);
for (iy=1; iy < Ny-1; iy++) {
    UNEW(0, iy, PUDX0, PUDY);
}
UNEW(0, iy, PUDX0, PUDYN);

// ix = [1..Nx-1], iy = Ny-1
for (ix=1; ix < Nx-1; ix++) {
    UNEW(ix, iy, PUDX, PUDYN);
}
UNEW(ix, iy, PUDXN, PUDYN);

// ix = Nx-1, iy = [0..Ny-2]
UNEW(ix, 0, PUDXN, PUDY0);
for (iy=1; iy < Ny-1; iy++) {
    UNEW(ix, iy, PUDXN, PUDY);
}

// ix = [1..Nx-2], iy = 0
for (ix=1; ix < Nx-1; ix++) {
    UNEW(ix, 0, PUDX, PUDY0);
}

// ix = [1..Nx-2], iy = [1..Ny-2]
for (ix=1; ix < Nx-1; ix++) {
    for (iy=1; iy < Ny-1; iy++) {
        UNEW(ix, iy, PUDX, PUDY);
    }
}

#undef UNEW
#undef PUDYN
#undef PUDY
#undef PUDY0
#undef PUDXN
#undef PUDX
#undef PUDX0
然而,这显然是供计算机处理,而不是供人阅读和以后修改。宏和注释也是为了帮助人们稍后需要更改。除非在原始代码中存在严重的性能问题,否则我个人更喜欢带有分支语句的原始循环。它可能会更慢,但如果有必要,它可以更容易调试!

答案 2 :(得分:1)

我用“序言,主循环,结语”语义重写了。

void update_u_new(double **u_new, double **u, double **u_old, int ix, int iy, double calc, double pudx, double pudy)
{
    u_new[ix][iy] = 2.0*u[ix][iy] - u_old[ix][iy] + calc*(pudx+pudy);   
}

//iterates iy=1 to Ny-1
void main_loop_iy(double **u, double **u_new, double **u_old, int ix, int Ny, double pudx, double calc2, double calc)
{
    int iy;
    for(iy=1; iy<Ny-1; ++iy)
    {
        double pudy = (u[ix][iy+1] + u[ix][iy-1] - 2.0*u[ix][iy])*(calc2);  
        update_u_new(u_new, u, u_old, ix, iy, calc, pudx, pudy); 
    }
}

void do_iy_given_ux(double **u, double **u_new, double **u_old, double *ux_m1, double *ux, double *ux_p1, int ix, int Ny, double calc1, double calc2, double calc)
{
    //prologue iy=0
    int iy=0;
    double pudx = (ux_p1[iy] + ux_m1[iy] - 2.0*ux[iy])*(calc1); 
    double pudy = (u[ix][1] + u[ix][Ny-1] - 2.0*u[ix][0])*(calc2);
    update_u_new(u_new, u, u_old, ix, iy, calc, pudx, pudy); 

    //main loop 1 <= iy < Ny-1
    main_loop_iy(u, u_new, u_old, ix, Ny, pudx, calc2, calc);

    //epilogue, iy = Ny-1
    iy = Ny-1;   
    pudy = (u[ix][0] + u[ix][Ny-2] - 2.0*u[ix][Ny-1])*(calc2); 
    update_u_new(u_new, u, u_old, ix, iy, calc, pudx, pudy); 
}

//assumes ix=0
void do_iy_ix0(double **u, double **u_new, double **u_old, int Nx, int Ny, double calc1, double calc2, double calc)
{
    int ix=0;
    do_iy_given_ux(u, u_new, u_old, u[Nx-1], u[ix], u[ix+1], ix, Ny, calc1, calc2, calc);
}

//assumes ix=1 to Nx-1
void do_iy_given_ix_main_loop(double **u, double **u_new, double **u_old, int ix, int Ny, double calc1, double calc2, double calc)
{
    do_iy_given_ux(u, u_new, u_old, u[ix-1], u[ix], u[ix+1], ix, Ny, calc1, calc2, calc);
}

//assumes ix=Nx-1
void do_iy_ixNm1(double **u, double **u_new, double **u_old, int Nx, int Ny, double calc1, double calc2, double calc)
{
    int ix = Nx-1;
    do_iy_given_ux(u, u_new, u_old, u[0], u[ix], u[ix-1], ix, Ny, calc1, calc2, calc);
}

int do_it(double **u, double **u_new, double **u_old, int Nx, int Ny, double calc, double calc1, double calc2)
{
    int ix = 0;

    //prologue ix=0
    do_iy_ix0(u, u_new, u_old, Nx, Ny, calc1, calc2, calc);

    //main loop on 1 <= ix < Nx-1
    for(ix=1; ix<Nx-1; ++ix)
    {
        do_iy_given_ix_main_loop(u, u_new, u_old, ix, Ny, calc1, calc2, calc);
    }

    //epilogue on ix = Nx-1
    do_iy_ixNm1(u, u_new, u_old, Nx, Ny, calc1, calc2, calc);

    return 0;
}