- 注册时间
- 2015-10-9
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 1218
- 在线时间
- 小时
|
发表于 2019-12-11 02:33:20
|
显示全部楼层
我先把我的代码贴出来吧。
使用到了mpfrc++,可以在 http://www.holoborodko.com/pavel/mpfr/ 下载。
用64位无符号定点数存储阶乘的十进制的开头,具体算法见 einit。
然后用emul逐项乘下一个数进行递推(可以每递推百万次用einit校正一次)。
搜索比较接近 pi/10*2^64 的值就行了。
- #include<mpreal.h>
- #pragma comment(lib,"mpfr-4.0.1.lib")
- #include<iostream>
- #include<intrin.h>
- typedef mpfr::mpreal real;
- //10^frac(log10(factorial(n)))*2^64/10
- uint64_t einit(uint64_t n){
- static const real log10e=1/mpfr::log(10);
- static const real p264=mpfr::pow(2,64);
- return (uint64_t)(p264*mpfr::pow(10,mpfr::frac(mpfr::lngamma(n+1)*log10e)-1));
- }
- //2^64/10 ~< e*n/10^k < 2^64
- uint64_t emul(uint64_t e,uint64_t n){
- //10^pos
- static uint64_t pow10[]={
- 1,10,100,1000,10000,
- 100000,1000000,10000000,100000000,1000000000,
- 10000000000,100000000000,1000000000000,10000000000000,100000000000000,
- 1000000000000000,10000000000000000,100000000000000000,1000000000000000000,10000000000000000000
- };
- static int shrn[]={3,6,9,13,16,19,23,26,29,33,36,39,43,46,49,53,56,59,63,66};
- //round(2^(64+shrn[pos])/10^(pos+1))
- static uint64_t inv10[]={
- 0xcccccccccccccccd,0xa3d70a3d70a3d70a,0x83126e978d4fdf3b,0xd1b71758e219652c,
- 0xa7c5ac471b478423,0x8637bd05af6c69b6,0xd6bf94d5e57a42bc,0xabcc77118461cefd,
- 0x89705f4136b4a597,0xdbe6fecebdedd5bf,0xafebff0bcb24aaff,0x8cbccc096f5088cc,
- 0xe12e13424bb40e13,0xb424dc35095cd80f,0x901d7cf73ab0acd9,0xe69594bec44de15b,
- 0xb877aa3236a4b449,0x9392ee8e921d5d07,0xec1e4a7db69561a5,0xbce5086492111aeb
- };
- //res = e*n
- uint64_t res[2];
- res[0]=_umul128(e,n,res+1);
- if(res[1]==0)return res[0];
- //shrt = res >> shrn[pos]
- int pos=0;
- uint64_t shrt;
- if(res[1]>=pow10[19]){
- pos=19;
- shrt=res[1]>>2;
- res[0]=0;
- }
- else{
- while(res[1]>=pow10[pos+1])++pos;
- shrt=res[1]<<64-shrn[pos]|res[0]>>shrn[pos];
- res[0]=res[1]>>shrn[pos]?inv10[pos]:0;
- }
-
- _umul128(shrt,inv10[pos],res+1);
- return res[0]+res[1];
- }
- int main(){
- mpfr::mpreal::set_default_prec(192);
- std::cout.precision(39);
- uint64_t iinit=0xdeadbeefbadcab1e,isize=1000000000;
- uint64_t eval=einit(iinit);
- for(uint64_t i=iinit+1;i<=iinit+isize;++i){
- eval=emul(eval,i);
- }
- std::cout<<eval<<std::endl;
- std::cout<<einit(iinit+isize)<<std::endl;
- return 0;
- }
复制代码
|
|