一、首先对于函数1:naive_rotate(幼稚的翻转!?)
void naive_rotate(int dim, pixel *src, pixel *dst)
{
int i, j;
for (i = 0; i < dim; i++)
for (j = 0; j < dim; j++)
dst[RIDX(dim-1-j, i, dim)] = src[RIDX(i, j, dim)];//一位数组模拟二维矩阵,RIDX为宏定义(i*dim+j)
}
1、优化1:
先看以下代码:
#include <iostream>
#include <ctime>
#define maxn 10000
using namespace std;
int test[maxn][maxn];
int main()
{
int tot=0;
clock_t st,en;
st=clock();
for(int j=0;j<maxn;j++)
{
for(int i=0;i<maxn;i++)tot=test[i][j];
}
en=clock();
cout<<en-st<<"ms\n";
st=clock();
for(int i=0;i<maxn;i++)
{
for(int j=0;j<maxn;j++)tot=test[i][j];
}
en=clock();
cout<<en-st<<"ms";
}
运行结果如下:
内外循环次序的改变导致时间的不同,根本在于寻址时间的差异。
对于rotate函数的语句:dst[RIDX(dim-1-j, i, dim)] = src[RIDX(i, j, dim)];
其中等号前相当于写入地址,等号后相当于从地址中读。我们因尽量优化写的寻址,因此交换循环次序:
void attemp2(int dim, pixel *src, pixel *dst)
{
int i,j,mid;
for (j = 0; j < dim; j++)
for (i = 0; i < dim; i++)
dst[RIDX(dim-1-j, i, dim)] = src[RIDX(i, j, dim)];
}
2、优化2:
因为测试样例全为32的倍数,因此可做4,8,16...的展开:
需要添加的语句分别为4*4,8*8,16*16
void attemp3(int dim, pixel *src, pixel *dst)
{
int i,j,mid;
//j对应外层循环展开,i对应内层循环展开
for (j = 0; j < dim; j++)
{
for (i = 0; i < dim; i+=4)
{
dst[RIDX(dim-1-j, i, dim)] = src[RIDX(i, j, dim)];
dst[RIDX(dim-1-j, i+1, dim)] = src[RIDX(i+1, j, dim)];
dst[RIDX(dim-1-j, i+2, dim)] = src[RIDX(i+2, j, dim)];
dst[RIDX(dim-1-j, i+3, dim)] = src[RIDX(i+3, j, dim)];
dst[RIDX(dim-1-j-1, i, dim)] = src[RIDX(i, j+1, dim)];
dst[RIDX(dim-1-j-1, i+1, dim)] = src[RIDX(i+1, j+1, dim)];
dst[RIDX(dim-1-j-1, i+2, dim)] = src[RIDX(i+2, j+1, dim)];
dst[RIDX(dim-1-j-1, i+3, dim)] = src[RIDX(i+3, j+1, dim)];
dst[RIDX(dim-1-j-2, i, dim)] = src[RIDX(i, j+2, dim)];
dst[RIDX(dim-1-j-2, i+1, dim)] = src[RIDX(i+1, j+2, dim)];
dst[RIDX(dim-1-j-2, i+2, dim)] = src[RIDX(i+2, j+2, dim)];
dst[RIDX(dim-1-j-2, i+3, dim)] = src[RIDX(i+3, j+2, dim)];
dst[RIDX(dim-1-j-3, i, dim)] = src[RIDX(i, j+3, dim)];
dst[RIDX(dim-1-j-3, i+1, dim)] = src[RIDX(i+1, j+3, dim)];
dst[RIDX(dim-1-j-3, i+2, dim)] = src[RIDX(i+2, j+3, dim)];
dst[RIDX(dim-1-j-3, i+3, dim)] = src[RIDX(i+3, j+3, dim)];
}
}
}
3、优化3:
循环的分块(简直就是个黑科技)
基本想法如下:若进行10000*10000二重循环的计算那么可以将将10000*10000的二重循环拆分成1000*1000个的10*10的二重循环这时分块的大小为10,或者拆成若干个5*5的二重循环,这时分块的大小为5。分块大小的不同将显著影响程序的运行速度(具体涉及深层的计算机原理,现在就当个STL样的东西用就好了,哈哈)
可见以下代码:
#include <iostream>
#include <ctime>
#define maxn 10000
using namespace std;
int map[maxn][maxn];
int main()
{
int tot=0;
clock_t st,en;
st=clock();
for(int i=0;i<maxn;i++)
{
for(int j=0;j<maxn;j++)
map[i][j];
}
en=clock();
cout<<en-st<<"ms\n";
tot=0;
st=clock();
int blocksize=5;
for(int i=0;i<maxn;i+=blocksize)
for(int j=0;j<maxn;j+=blocksize)
{
for(int jj=j;jj<j+blocksize;jj++)
for(int ii=i;ii<i+blocksize;ii++)
map[ii][jj];
}
en=clock();
cout<<en-st<<"ms\n";
}
于是得到优化3的代码:
void attemp4(int dim, pixel *src, pixel *dst)
{
int i,j,ii,jj,mid,blocksize=32;//因为样例为32的倍数,所以块的大小可分为(32*k)*(32*k)
//注意一下四个循环的次序,进行调换会显著影响时间
for(i=0;i<dim;i+=blocksize)
for(j=0;j<dim;j+=blocksize)
{
for(jj=j;jj<j+blocksize;jj++)
for(ii=i;ii<i+blocksize;ii++)
dst[RIDX(dim-1-jj, ii, dim)] = src[RIDX(ii, jj, dim)];
}
}
待更。。。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------