找回密码
 欢迎注册
楼主: medie2005

[讨论] 阶乘和圆周率

  [复制链接]
发表于 2010-8-23 20:56:07 | 显示全部楼层
我重读这个帖子,期待对另外一个问题程序的改进
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-8-24 09:25:04 | 显示全部楼层
我期待这个题有一个新的突破
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-10-31 08:09:30 | 显示全部楼层
如果允许小数的话,问题就变得很简单了。 比如 n!=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446 E1000000000000 那么n=94851898540.1396977006676482198750221184274755718919148371815155857816611145105279808242712122064124653944534478504904850688162913
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-12-1 20:22:20 | 显示全部楼层
1# medie2005 做新手任务,凑字数
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-12-3 18:16:10 | 显示全部楼层
这个题目真的很有意思!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-12-4 16:16:05 | 显示全部楼层
1# medie2005 难度确实挺大
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-12-6 18:08:52 | 显示全部楼层
我曾发过帖子说2的幂能以任何数字开始 这个问题和那帖子上的问题类似 但更难做了 无心人 发表于 2008-12-4 11:38
Matlab?

评分

参与人数 1金币 +20 收起 理由
gxqcn + 20 首帖奖励,欢迎常来。

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-12-12 14:56:54 | 显示全部楼层
62# 无心人 今天仔细考虑了这个题目。我认为无需使用大数库。无心人的程序中调用了大数库,而且用到对数,故速度较慢。其实这个题目虽然需要做高精度计算,但只用到小整数乘以大数的运算,完全可以自己实现。我刚刚写了一个程序,未用到任何大数库。这个程序从1开始,一直查找到2^32-1,在我的电脑上只需要3分钟左右。 说明: 1. 我在程序中设定的精度是4个DWORD,每个DWORD表示9位10进制数,故最大精度不超过36位,若需更高精度,则只需改动一处即可。 2. 目前的代码最多可计算到2^32-1,若需要扩大搜索范围,需要实现一个64bit数和大数相乘的算法。 3. 我的程序依次计算每个32位整数n,求n!的科学计数法表示和pi的差,若其差小于当前的最小值,则输出n和n!. 下面是我的程序的输出结果:
  1. 20!=2.432902008176640000*10^18
  2. 23!=2.5852016738884976640000*10^22
  3. 28!=3.04888344611713860501504000000*10^29
  4. 154!=3.0897696138473508879585646636*10^271
  5. 332!=3.1034430734498676144426322732*10^694
  6. 612!=3.1345284031431087019726722580*10^1441
  7. 2703!=3.1398094010536875630936179148846*10^8104
  8. 8945!=3.139993064736104560624185498*10^31464
  9. 17254!=3.14084642621024495446191444792*10^65612
  10. 28726!=3.14106463595708329690285209393642766*10^115595
  11. 50583!=3.1415379577347882738422653077918*10^215977
  12. 527600!=3.14155838836242816120923043886*10^2789957
  13. 780018!=3.1415890794236473559982729593497*10^4257193
  14. 1812538!=3.141589535267260763834817102767*10^10556211
  15. 5385973!=3.141591234607732809306850985*10^33915312
  16. 5573998!=3.14159238184880918674222498012222406*10^35182367
  17. 52604972!=3.1415925665166406146782547740*10^383318353
  18. 65630447!=3.141592602756036723755404377401952*10^484537182
  19. 187024036!=3.141592617297502030148476882134*10^1465820139
  20. 410390476!=3.141592622630656164649753699858562*10^3356543814
  21. 464736214!=3.14159264915921444226889681595*10^3826132373
  22. 688395641!=3.141592651962886290907283002629*10^5784962808
  23. It took 188 secs
复制代码

评分

参与人数 1贡献 +10 鲜花 +10 收起 理由
gxqcn + 10 + 10 很巧的方法,难得的结果!

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-12-12 14:59:02 | 显示全部楼层
  1. #include "stdlib.h"
  2. #include "stdio.h"
  3. #include "string.h"
  4. #include "windows.h"
  5. typedef __int64 INT64;
  6. typedef unsigned long DWORD;
  7. #define DEC_RADIX 1000000000
  8. #define PRECISION_DIV9 4 //10进制数表示的数字个数除以9
  9. const DWORD PI_VALUE[][2]={
  10. {3,141592653},
  11. {31,415926535},
  12. {314,159265358},
  13. {3141,592653589},
  14. {31415,926535897},
  15. {314159,265358979},
  16. {3141592,653589793},
  17. {31415926,535897932},
  18. {314159265,358979323},
  19. };
  20. double scales[]=
  21. {
  22. 1.00,
  23. 10.00,
  24. 100.00,
  25. 1000.00,
  26. 10000.00,
  27. 100000.00,
  28. 1000000.00,
  29. 10000000.00,
  30. 100000000.00,
  31. };
  32. int Uint32BitCount(DWORD n)
  33. {
  34. _asm
  35. {
  36. bsr eax,n
  37. inc eax
  38. }
  39. }
  40. //******************************************************
  41. DWORD DEC_Array_Mul_DWORD_ALU(DWORD *a, size_t len, DWORD num)
  42. //******************************************************
  43. {
  44. static DWORD _s_TEN9=DEC_RADIX;
  45. //---------------------------
  46. _asm
  47. {
  48. push esi
  49. mov ecx,len
  50. mov esi,a
  51. lea esi,[esi+ecx*4-4]
  52. xor ecx,ecx //carry
  53. test esi,3 //the a must be 4byte align
  54. jnz thisExit
  55. jmp cmp000
  56. loop_start:
  57. mov eax,[esi]
  58. mul dword ptr num
  59. add eax,ecx
  60. adc edx,0
  61. div dword ptr _s_TEN9
  62. mov [esi],edx
  63. mov ecx,eax
  64. sub esi,4
  65. cmp000:
  66. cmp esi,a
  67. jae loop_start
  68. thisExit:
  69. mov eax,ecx
  70. pop esi
  71. }
  72. }
  73. double check_diff(DWORD num[],int shift)
  74. {
  75. int t,carry;
  76. DWORD tArr[2];
  77. tArr[0]=PI_VALUE[shift][0];
  78. tArr[1]=PI_VALUE[shift][1];
  79. t=tArr[1]-num[1];
  80. if (t<0)
  81. {
  82. carry=1;
  83. t+=DEC_RADIX;
  84. }
  85. else
  86. carry=0;
  87. tArr[1]=t;
  88. t=tArr[0]-num[0]-carry;
  89. tArr[0]=t;
  90. if (t<0)
  91. {
  92. return 999;
  93. }
  94. else
  95. {
  96. double diff;
  97. diff =tArr[0] + tArr[1] * 0.000000001;
  98. diff /= scales[shift];
  99. return diff;
  100. }
  101. }
  102. void print_number(DWORD n,DWORD res[],int len,double exp)
  103. {
  104. char buff[PRECISION_DIV9*9+9];
  105. char *p;
  106. int i,s;
  107. INT64 e;
  108. p=buff;
  109. p+=sprintf(p,"%d",res[0]);
  110. s=strlen(buff);
  111. if (len>1)
  112. {
  113. for (i=1;i<len;i++)
  114. p+=sprintf(p,"%09d",res[ i ]);
  115. }
  116. printf("\n%u!=",n);
  117. for (i=0;i<strlen(buff);i++)
  118. {
  119. printf("%c",buff[ i ]);
  120. if (i==0)
  121. printf(".");
  122. }
  123. e=(INT64)(exp+(len-1)*9+s-1);
  124. printf("*10^%I64d\n",e);
  125. }
  126. void search_n()
  127. {
  128. DWORD i,j;
  129. DWORD carry;
  130. int shift;
  131. int bc,fac_len; // fac(i)的结果的数组的长度
  132. double diff,min_diff;
  133. double res_exp;
  134. DWORD fac[PRECISION_DIV9+1]; //fac(i)的结果的数组
  135. DWORD time;
  136. time=GetTickCount();
  137. min_diff=1;
  138. res_exp=0;
  139. fac[0]=1;
  140. fac_len=1;
  141. i=1;
  142. //while (i<DEC_RADIX)
  143. while (i!=0)
  144. {
  145. carry=DEC_Array_Mul_DWORD_ALU(fac,fac_len,i);
  146. if (carry>=DEC_RADIX)
  147. {
  148. for (j=PRECISION_DIV9-2;j>=2;j--)
  149. fac[j]=fac[j-2];
  150. fac[0]=carry / DEC_RADIX;
  151. fac[1]=carry % DEC_RADIX;
  152. if ( fac_len+2 <= PRECISION_DIV9)
  153. fac_len+=2;
  154. else if (fac_len+1 ==PRECISION_DIV9)
  155. {
  156. fac_len=PRECISION_DIV9;
  157. res_exp+=9;
  158. }
  159. else
  160. res_exp+=18;
  161. }
  162. else if (carry>0)
  163. {
  164. for (j=PRECISION_DIV9-1;j>=1;j--)
  165. fac[j]=fac[j-1];
  166. fac[0]=carry;
  167. if (fac_len<PRECISION_DIV9)
  168. fac_len++;
  169. else
  170. res_exp+=9;
  171. }
  172. bc=Uint32BitCount(fac[0]);
  173. switch (bc)
  174. {
  175. case 2:
  176. shift=0;
  177. diff=check_diff(fac,shift);
  178. if (diff<min_diff)
  179. {
  180. min_diff=diff;
  181. if (fac_len>=2)
  182. print_number(i,fac,fac_len,res_exp);
  183. }
  184. break;
  185. case 5:
  186. shift=1;
  187. diff=check_diff(fac,shift);
  188. if (diff<min_diff)
  189. {
  190. min_diff=diff;
  191. if (fac_len>=2)
  192. print_number(i,fac,fac_len,res_exp);
  193. }
  194. break;
  195. case 9:
  196. shift=2;
  197. diff=check_diff(fac,shift);
  198. if (diff<min_diff)
  199. {
  200. min_diff=diff;
  201. if (fac_len>=2)
  202. print_number(i,fac,fac_len,res_exp);
  203. }
  204. break;
  205. case 12:
  206. shift=3;
  207. diff=check_diff(fac,shift);
  208. if (diff<min_diff)
  209. {
  210. min_diff=diff;
  211. if (fac_len>=2)
  212. print_number(i,fac,fac_len,res_exp);
  213. }
  214. break;
  215. case 15:
  216. shift=4;
  217. diff=check_diff(fac,shift);
  218. if (diff<min_diff)
  219. {
  220. min_diff=diff;
  221. if (fac_len>=2)
  222. print_number(i,fac,fac_len,res_exp);
  223. }
  224. break;
  225. case 19:
  226. shift=5;
  227. diff=check_diff(fac,shift);
  228. if (diff<min_diff)
  229. {
  230. min_diff=diff;
  231. if (fac_len>=2)
  232. print_number(i,fac,fac_len,res_exp);
  233. }
  234. break;
  235. case 22:
  236. shift=6;
  237. diff=check_diff(fac,shift);
  238. if (diff<min_diff)
  239. {
  240. min_diff=diff;
  241. if (fac_len>=2)
  242. print_number(i,fac,fac_len,res_exp);
  243. }
  244. break;
  245. case 25:
  246. shift=7;
  247. diff=check_diff(fac,shift);
  248. if (diff<min_diff)
  249. {
  250. min_diff=diff;
  251. if (fac_len>=2)
  252. print_number(i,fac,fac_len,res_exp);
  253. }
  254. break;
  255. case 29:
  256. shift=8;
  257. diff=check_diff(fac,shift);
  258. if (diff<min_diff)
  259. {
  260. min_diff=diff;
  261. if (fac_len>=2)
  262. print_number(i,fac,fac_len,res_exp);
  263. }
  264. break;
  265. default:
  266. break;
  267. }
  268. i++;
  269. }
  270. time=(GetTickCount()-time);
  271. printf("It took %d secs\n",time/1000);
  272. }
  273. int main(int argc, char* argv[])
  274. {
  275. search_n();
  276. return 0;
  277. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2012-12-12 21:34:01 | 显示全部楼层
刚才仔细看了一下无心人的代码,明白了其所用的算法。其主要算法如下, 从start开始,逐个计算每个整数n的阶乘的常用对数的小数部分,记作log(fac(n)), 和PI的常用对数的小数部分比较,符合条件则输出。 当n是1000的整数倍时,计算base=n, lf0=log10(fac(base))的小数部分, 若n不是base的整数倍时,则计算从base+1到n之间所有数的累乘积的自然对数的小数部分lf1, 则 n!的对数的小数部分为 lf= lf0+lf1。 无心人的算法主要受制于 c语言库中(或者CPU浮点指令)中的双精度数的对数函数精度的制约,很难提高精度。 受无心人的启发,我打算编写一个不使用求双精度对数和多重精度对数函数的程序。 主要特点有: 1. 可计算到10^15或者更高。 2. 可分段计算。 3. 当n小于10亿时,使用自己写的多重精度大数乘以32bit整数的子程序,计算n的阶乘,fac(n),以10^9进制表示. 当n>=10亿且n是100万的倍数时,使用斯特林公式的普通形式(而不是指数形式)计算 fac(n),以10^9进制表示,记作fac_0 当n>10亿且n不是100万的倍数时,令n=base+d(base是100万的整数倍,d>0 且 d
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-12-22 09:42 , Processed in 0.036245 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表