liangbch 发表于 2008-12-8 10:37:00

回复29楼,那是很久以前的事了,代码不好找了。

无心人 发表于 2008-12-8 14:43:57

#include <gmp.h>
#include <mpfr.h>
#include <stdio.h>

#define DefaultBitLength 128

int main(void)
{
mpfr_t a, b, low, hi, lf, t;
double dLow, dHi, dLf, dA;
int find = 0;
long i = 0;

mpfr_init2(a, DefaultBitLength);
mpfr_set_d(a, 2.0, GMP_RNDD);
mpfr_init2(b, DefaultBitLength);
mpfr_set_d(b, 1.0, GMP_RNDD);
mpfr_init2(low, DefaultBitLength);
mpfr_init2(hi, DefaultBitLength);
mpfr_init2(lf, DefaultBitLength);
mpfr_set_d(lf, 0.0, GMP_RNDD);
mpfr_init2(t, DefaultBitLength);

printf("请输入上界: ");
scanf("%lf", &dHi);
printf("请输入下界: ");
scanf("%lf", &dLow);

//printf("当前界限[%f, %f]\n", dLow, dHi);

mpfr_set_d(low, dLow, GMP_RNDD);
mpfr_set_d(hi, dHi, GMP_RNDD);

mpfr_log10(low, low, GMP_RNDD);
mpfr_log10(hi, hi, GMP_RNDD);

while (1)
{
    mpfr_log10(t, a, GMP_RNDD);
    mpfr_add(lf, lf, t, GMP_RNDD);

    if (mpfr_cmp_d(lf, 1.0) >= 0)
      mpfr_sub_ui(lf, lf, 1, GMP_RNDD);

    if ((mpfr_cmp(lf, low) >= 0)&& (mpfr_cmp(lf, hi) < 0))
   {
       find = 1;
       break;
   }

    mpfr_add(a, a, b, GMP_RNDD);

    if (mpfr_cmp_d(a, 10.0) >= 0)
    {
      i++;
      mpfr_div_ui(b, b, 10, GMP_RNDD);
      mpfr_add_ui(a, b, 1, GMP_RNDD);
    }
   
}

if (find)
{
    dLf = mpfr_get_d1(lf);
    while (i > 0)
    {
      mpfr_mul_ui(a, a, 10, GMP_RNDD);
      i--;
    }
    dA = mpfr_get_d1(a);
   
    printf("当前界限下的阶乘%.0f!, 对应的对数%.15f", dA, dLf);
}

mpfr_clear(a);
mpfr_clear(b);
mpfr_clear(low);
mpfr_clear(hi);
mpfr_clear(lf);
mpfr_clear(t);
return 1;
}

////////////////////////////////////////////////////////
利用mpfr可写出适合超过100000000的阶乘的一个寻找程序
但似乎速度慢很多哦

无心人 发表于 2008-12-8 16:47:37

使用这个库之后
速度巨慢了

上次的程序,十几分钟就能计算出
314159265的结果

无心人 发表于 2008-12-9 08:30:29

经过一夜的运算找到了
起始数字314159265的结果
在20#
用PARI计算的0.497149872468489(程序输出的,转换为Double, 真实的是96Bit浮点)对应的数字
希望有人进行复检

另外,下个数字运算程序可能就要写定时状态保存了,而且要用128位浮点了
唯一的好处是这个程序基本是线性时间

mathe 发表于 2008-12-9 08:43:53

没有问题,我用striling公式带入windows计算器验算了一下,结果为:
3.14159265196...
而Windows计算机浮点精度挺高的。

无心人 发表于 2008-12-9 08:48:48

32#程序是在MinGW+ GCC4.21下编译通过的
预先编译了GMP 4.2.4和MPFR2.3.2,均是静态库形式

gcc factPi.c -std=c99 -O2 -lmpfr -lgmp -o factPi.exe
编译

可脱离MinGW运行
有兴趣的童鞋
我可以上传一个包
覆盖在MINGW的 include和lib就能使用

无心人 发表于 2008-12-9 08:56:16

.h放mingw\include
其他放 mingw\lib
安装msys进入模拟unix环境gcc编译

无心人 发表于 2008-12-9 13:51:57

在把浮点数保存在文件里时遇到困难
不知道如何写
MPFR这方面的资料太少了
mpfr_out_str不能用
mpfr_get_str怎么不能保存小数点?

无心人 发表于 2008-12-15 19:31:22

今天想到一个新思路

计算了
log(3.141592653590) = 0.4971498726941624371131490186099
log(3.141592653589) = 0.49714987268172081667353310595166
二者的差是1.3824022710488533020286478680411e-13
约等于2^(-42.717887740820254037211382936331 )
考虑double的精度是2^(-53)
显然只要最终数字的精度大于2^(-43)即可
那么如果我们用MPFR每隔1024隔数字
用strling公式
计算一个精度在2^(-53)的准确的阶乘的log值
而之间的数字则使用double类型的log进行连加
则中间状态的精度肯定大于2^(-43)
===========================
为了防止边界溢出现象
我们可以考虑使用long double类型
则此时的机器精度是2^(-63)

无心人 发表于 2008-12-15 19:36:20

在long double情况下

Prelude> let a = 3.14159265358979
Prelude> let b = 3.14159265358980
Prelude> log(b) / log(10) - log(a) / log(10)
1.4432899320127035e-15
Prelude> log(it) / log(2)
-49.29956028185891
Prelude> it + 10
-59.29956028185891

即保守估计可以计算到314159265358979
页: 1 2 3 [4] 5 6 7 8 9 10 11 12 13
查看完整版本: 阶乘和圆周率