我在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);
}
}
答案 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
内容并使其更明确。它更长,但它可以节省您可能耗时的分支和模/分计算。我使用预处理器宏来使事情更清晰,并减少复制粘贴错误的可能性。宏应该本地化为相关代码,否则calc1
和u_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;
}