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; }
时间: 2024-10-10 09:44:39