写了一个计算pi值的c语言程序:
https://github.com/gongchengra/hacker/blob/master/c/16_pi.c
全部代码如下:
#include <stdio.h>
#define NUMBER 100000
int array_divide_number(int *array, int number, int size)
{
int i,tmp;
int modulo=0;
for(i=0;i<size;i++)
{
tmp = array[i]+modulo*10;
array[i] = tmp/number;
modulo = tmp%number;
}
return 0;
}
void print_array(int *array, int size)
{
int i,last;
for(last=size-1;last>=0;last--)
{
if(array[last] != 0)
{
break;
}
}
for(i=0;i<=last;i++)
{
printf("%d",array[i]);
}
printf("\n");
}
void copy_array(int *source, int *target, int size)
{
int i;
for(i=0;i<size;i++)
{
target[i] = source[i];
}
}
void plus_array(int *augend, int *addend, int *sum, int size)
{
int i;
for(i=size-1;i>=0;i--)
{
sum[i] = augend[i] + addend[i];
if(sum[i]>9)
{
sum[i] = sum[i] % 10;
sum[i-1]++;
}
}
}
void minus_array(int *minuend, int *subtracter, int *answer, int size)
{
int i;
for(i=size-1;i>=0;i--)
{
if(minuend[i] >= subtracter[i] || i == 0)
{
answer[i] = minuend[i] - subtracter[i];
}
else
{
if(minuend[i-1] == 0)
{
minuend[i-2]--;
minuend[i-1] = 10;
}
minuend[i-1]--;
answer[i] = 10 + minuend[i] - subtracter[i];
}
}
}
int main()
{
int i;
int flag=1;
int d5[NUMBER]={0};
int t5[NUMBER]={0};
int d239[NUMBER]={0};
int t239[NUMBER]={0};
int pi[NUMBER]={0};
d5[0]=16;
d239[0]=4;
array_divide_number(d5,5,NUMBER);
array_divide_number(d239,239,NUMBER);
//every iteration will increase three valid digitals
for(i=1;i<NUMBER*3/2;i+=2)
{
copy_array(d5, t5, NUMBER);
copy_array(d239, t239, NUMBER);
array_divide_number(t5,i,NUMBER);
array_divide_number(t239,i,NUMBER);
if(flag > 0)
{
plus_array(pi,t5,pi,NUMBER);
minus_array(pi,t239,pi,NUMBER);
}
else
{
minus_array(pi,t5,pi,NUMBER);
plus_array(pi,t239,pi,NUMBER);
}
flag = -1*flag;
array_divide_number(d5,5*5,NUMBER);
array_divide_number(d239,239*239,NUMBER);
}
print_array(pi, NUMBER);
return 0;
}
程序可以工作,但是需要的时间太久,
time ./16_pi.exe >pi3.log
./16_pi.exe > pi3.log 617.76s user 0.15s system 98% cpu 10:27.94 total
计算pi的十万位需要617秒,将近十分钟,请教SF上的达人,在不改变计算pi的算法前提下有没有办法可以优化程序来减少程序运行的时间?
刚好考完试比较闲,所以上午都在优化这个程序:)。
试了各种优化方法,有些方法行有些不行,不行的这里就略过。
另外,因为各人的电脑不同,所以不要看绝对的数据,看相对值的变化就好了。
说说我的过程:
编译器选项优化
考虑lz的代码应该是release版本的,对应的就是
-O2
选项,那么试试gcc -O2
,定下基值:然后试一下各种编译器选项,最后确定
-O3
的效果最好。检查下生成输出文件的md5,跟优化前一致。
之后又试了别的编译器,最好的还是用gcc。
代码上的优化
不能改算法,那么就替换掉部分函数。
比如,把
copy_array
改成memcpy
,结果跑到了2.30s。又试了下,把int数组全改成short,结果没有变化囧。
试着分拆下for循环。发现把
array_divide_number
拆成一次性算5个,居然能跑到2.28s。(不是偶然,多次重复运行都能达到差不多的结果)循环拆开有时候能够提高运算效率,不过具体有没有效果基本靠运气……
然后又试了下其他的小修小补,没多大影响。
最后试了下,用宏代替所有的函数。依然没变化。
看来在编译器使用
-O3
优化后,靠微调代码的优化已经没有多大空间了。进一步的优化?
如果要进一步做优化,可以考虑下利用特殊的硬件提高运算效率,比如GPU或者MIC之类的。因为我手头上没有“特殊的硬件”,所以这一步就没有尝试了。
有条件可以试一下:)
总结:
贴个最后的结果:
从258.91s优化到238.82s,嗯。
最后的代码: