- 注册时间
- 2008-2-6
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 51573
- 在线时间
- 小时
|
发表于 2008-12-21 21:37:29
|
显示全部楼层
修改了代码
使用gcc -O2 -ffast-math -march=pentium4 factpi1.c -o factpi1.exe -lmpfr -lgmp-
- #include <gmp.h>
- #include <mpfr.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <sys/time.h>
-
- #define DefaultBitLength 128
- #define TEST
-
- mpfr_t ln10, cA, cT;
-
- FILE * fp;
-
- //=1/2ln(2π)+(n+1/2)ln(n)-n+1/12n
- //n > 10^8 误差<1/360Z^3 = 10^(-26)
- long double stirling(double n)
- {
- mpfr_t a, b, c, s;
- long double r;
-
- mpfr_init2(a, DefaultBitLength);
- mpfr_init2(b, DefaultBitLength);
- mpfr_set_d(a, n, GMP_RNDD); //a=n
- mpfr_init2(c, DefaultBitLength);
- mpfr_init2(s, DefaultBitLength);
-
- mpfr_div(s, cT, a, GMP_RNDD); //s = 1/12a = 1/12n
- mpfr_sub(s, s, a, GMP_RNDD); //s = s - a = - n + 1/12n
-
- mpfr_log(c, a, GMP_RNDD); //c = ln(n)
-
- mpfr_set_d(b, 0.5, GMP_RNDD);
- mpfr_add(b, a, b, GMP_RNDD);
- mpfr_mul(b, b, c, GMP_RNDD); //b = (n + 1/2)ln(n)
-
- mpfr_add(s, s, b, GMP_RNDD); //s = (n + 1/2)ln(n) - n + 1/12n
-
- mpfr_add(s, s, cA, GMP_RNDD); //最终结果s=1/2ln(2*pi) + (n + 1/2)ln(n) - n + 1/12n
-
- mpfr_mul(s, s, ln10, GMP_RNDD); //转换为log10
- mpfr_floor(b, s);
- mpfr_sub(s, s, b, GMP_RNDD); //只要小数
-
- r = mpfr_get_ld(s, GMP_RNDD);
-
- mpfr_clear(a);
- mpfr_clear(b);
- mpfr_clear(c);
- mpfr_clear(s);
- return r;
- }
-
- int main(void)
- {
- double a, b, low, hi, lf, t;
- double start, used_time;
- int find = 0, test1 = 0;
- long i, j = 0;
- struct timeval start_time, end_time;
-
- mpfr_init2(ln10, DefaultBitLength);
- mpfr_init2(cA, DefaultBitLength);
- mpfr_init2(cT, DefaultBitLength);
- mpfr_set_ui(ln10, 10, GMP_RNDD);
- mpfr_set_ui(cT, 1, GMP_RNDD);
-
- mpfr_log(ln10, ln10, GMP_RNDD);
- mpfr_div(ln10, cT, ln10, GMP_RNDD);
-
- mpfr_const_pi(cA, GMP_RNDD);
- mpfr_mul_ui(cA, cA, 2, GMP_RNDD);
- mpfr_log(cA, cA, GMP_RNDD);
- mpfr_div_ui(cA, cA, 2, GMP_RNDD);
-
- mpfr_div_ui(cT, cT, 12, GMP_RNDD);
-
- printf("请输入起始搜索数字:");
- scanf("%lf", &start);
- printf("请输入上界: ");
- scanf("%lf", &hi);
- printf("请输入下界: ");
- scanf("%lf", &low);
- fp = fopen("factpi.log", "a+t");
- printf("起始位置:%.0f\n当前界限[%.17f, %.17f]\n", start, low, hi);
- fprintf(fp, "\n///////////////////////////////////////////////////////////////\n");
- fprintf(fp, "起始位置:%.0f\n当前界限[%.17f, %.17f]\n", start, low, hi);
-
- hi = log10(hi);
- low = log10(low);
-
- printf("当前对数界限[%.17f, %.17f]\n", low, hi);
- fprintf(fp, "当前对数界限[%.17f, %.17f]\n", low, hi);
- a = start;
- b = 1.0;
- while (a >= 10.0)
- {
- a /= 10.0;
- b *= 10.0;
- }
-
- lf = 2.0;
- gettimeofday(&start_time, NULL);
- for (i = 0; i < 1000; i ++)
- lf += stirling(lf + 100000000.0);
- gettimeofday(&end_time, NULL);
- used_time = ((end_time.tv_sec - start_time.tv_sec)*1000000.0 + (end_time.tv_usec - start_time.tv_usec)) / 1000.0;
- printf("高精度stirling函数执行时间(毫秒): %8.6lf, 测试值:%.8lf\n", used_time, lf);
- fprintf(fp, "高精度stirling函数执行时间(毫秒): %8.6lf, 测试值:%.8lf\n", used_time, lf);
-
- lf = stirling(start);
- printf("起始对数: %.17f\n", lf);
- fprintf(fp, "起始对数: %.17f\n", lf);
- fflush(fp);
- gettimeofday(&start_time, NULL);
-
- i = 0;
- while (1)
- {
- if ((a = log10((start += 1.0)/b)) >= 1.0)
- {
- b *= 10.0;
- a -= 1.0;
- }
-
- if ((lf += a) >= 1.0)
- lf -= 1.0;
-
- // printf("[%.0f, %.15f] ", start, lf);
-
- if ((lf >= low) && (lf < hi))
- {
- find = 1;
- break;
- }
-
- if (( ++i) >= 1000)
- {
- lf = stirling(start);
- i = 0;
- j ++;
- #ifdef TEST
- if (j >= 1000)
- {
- if (test1 == 0)
- {
- gettimeofday(&end_time, NULL);
- used_time = ((end_time.tv_sec - start_time.tv_sec)*1000000.0 + (end_time.tv_usec - start_time.tv_usec))/1000000.0;
- printf("每10^6次查找执行时间(秒): %.6lf\n", used_time);
- test1 = 1;
- }
- }
- #else
- if (j >= 100000000)
- {
- j = 0;
- fprintf(fp, "当前搜索数值: %.0f\n", start);
- fflush(fp);
- }
- #endif
- }
- }
-
- if (find)
- {
- printf("\n当前界限下的阶乘%.0f!, 对应的对数%.15f", start, lf);
- fprintf(fp, "\n当前界限下的阶乘%.0f!, 对应的对数%.15f", start, lf);
- }
-
- mpfr_clear(ln10);
- mpfr_clear(cA);
- mpfr_clear(cT);
- fclose(fp);
- return 1;
- }
复制代码
==========================================================
请输入起始搜索数字:100000000
请输入上界: 3.1415927
请输入下界: 3.1415926
起始位置:100000000
当前界限[3.14159260000000010, 3.14159269999999990]
当前对数界限[0.49714986528586863, 0.49714987910989134]
高精度stirling函数执行时间(毫秒): 30.044000, 测试值:493.74586181
起始对数: 0.20876475177585671
每10^6次查找执行时间(秒): 0.170244
当前界限下的阶乘149832529!, 对应的对数0.497149873593338
========================================================
经过查询汇编代码,程序已经被gcc优化到了很好的程度
相对以前,执行时间已经缩小了很多了
使用了P6以上的fcomi和直接的log指令, 另外,其最终的对数值精度提高了
==========================================================
P4 2.0 /1G DDR/XP SP3 |
|