hdu 6217 A BBP Formula 公式题

https://zh.wikipedia.org/wiki/%E8%B4%9D%E5%88%A9-%E6%B3%A2%E5%B0%94%E6%B8%A9-%E6%99%AE%E5%8A%B3%E5%A4%AB%E5%85%AC%E5%BC%8F

http://blog.csdn.net/meopass/article/details/78327614

这类公式是用来求解一些无理数常数的公式,特点是不需要求解前n-1位也能去算第n位

假设你得到了PI,那么你求十六进制下第n位,只需要把在16进制下的小数点挪到第n-1位和第n位之间,即*16^(n-1),然后去掉整数部分,小数部分再乘16得到的整数部分即是第n位咯

那么如此一来,我们要计算的就是这小数部分咯

对于原累加式,乘16^(n-1)后,由于整数部分可以不管它,那么就让16^(n-1)mod对应的分母,这样小数部分已然不变

对于前n-1项可以如此,那么对于第n项到正无穷项,为了保持精度应该算多少嘞

首先分析精度,小数部分*16得到整数部分就是第n位,小数部分的精度应该要保证*16不影响整数位,对于第n项到正无穷项,对于小数部分的误差是可以允许的

假设最极端的情况下计算小数点后1位,那么要计算的第n项是0.008089 已经小于1e-2 ,乘16的误差也在1e-1以内,如此一来,当n比较大的时候,误差会更小,应该是可以放弃计算第n项到后面的

#include <bits/stdc++.h>

using namespace std;
#define maxn 100010
#define LL long long
//#define double long double
LL quickpower(LL a,LL b,LL MOD )
{
    LL r=1;
    while(b>0)
    {
        if(b&1LL)r=r*a%MOD;
        a=a*a%MOD;
        b>>=1LL;
    }
    return r;
}
double BBP(int n,double a,double b){
    double r=0;
    for(int k=0;k<=n;k++) r+=quickpower(16,n-k,8*k+b)*1.0/(k*8.0+b);
   // for(int k=n+1;k<=n+1000;k++) r+=1/(k*8.0+b)/pow(16,k-n);
    return r*a;
}
double BBPformular(int n){
    return BBP(n,4,1)+BBP(n,-2,4)+BBP(n,-1,5)+BBP(n,-1,6);
}

int main(){
#ifdef shuaishuai
    freopen("C:\\Users\\hasee\\Desktop\\a.txt","r",stdin);
  // freopen("C:\\Users\\hasee\\Desktop\\b.txt","w",stdout);
#endif
    int t;
    scanf("%d",&t);
    for(int c=1;c<=t;c++){
        int n;
        scanf("%d",&n   );
        n--;
        double r=BBPformular(n);
        r=r-(LL)r;
       // printf("%.10f\n",r);
        if(r<0)r+=1.0;
        r*=16;
        int res=r;
        //printf("res:%d r*16:%f\n",res,r);
        printf("Case #%d: %d %c\n",c,n+1,res>9? res-10+'A':res+'0');
    }

    return 0;
}

 

posted @ 2017-11-05 16:26  MeowMeowMeow  阅读(636)  评论(0编辑  收藏  举报