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

[提问] 当n=?时,含9的项之和开始大于不含9的项之和

[复制链接]
发表于 2010-12-1 18:53:16 | 显示全部楼层
当我用不超过100ms的时间解决了,用时要14s 的这个问题的时候,我泪流满面!!!!!!!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-12-1 19:55:28 | 显示全部楼层
公式编辑器不太熟,还是百度贴吧的形式吧。
上面的情形对S9的情形处理的很好了。通过用欧拉公式,我想没有比这更好的了。只降到了3秒的运行时间,不错。但我还是不太满意,今天上课的时间突然想起了这事,也就思考了一下,发现还有潜力。
并且很优美。
当然是对不含9的情形,是不是觉得n=8,n=9时计算其仍然要不少的时间呢,所以从这里动刀,看能否将这两项的不含9的计算时间砍到0。
我首先想到的仍然是欧拉公式,这个的确没得说。细看#89楼的search_x()系列的循环,觉得可以用欧拉公式,并且很一致。
想法:
当n,m均较大时,有估计式:ln(n) - ln(m)=1/n  +1/(n-1)    +   ... +1/(m-1)
比如:对于n=8时的情形有:
search_8()
=(ln10000008 - ln9999999)  + (ln10000018 -ln10000009) + ...+ (ln88888888 -ln 88888879)
=ln(10000008/9999999)  + ln(10000018/10000009)   +  ... + ln(88888888/88888879)
=ln(1+9/9999999) + ln(1+9/10000009) +.... +ln(1+9/88888879)
到这里,你一定会有想法了,呵呵。没错,我们知道当x趋于0时,有估计式:ln (1+x) =x
好了,问题得到了简化:
=9/9999999 +9/10000009 + .... + 9/88888879
=9* (1/9999999+1/10000009+... +1/88888879)
是不是有点爽,发现这样一来,分母每次增量变成了10,几乎节省了一个数量级的除法次数。
但不太妙,这还是不好算啊,你很快会想到精度要求不太高的情形下,1/9999999=1/10000000于是有:
=9* (1/10000000+1/10000010 + ... +1/88888880)
嗯,不错了,.....,不是说了分母是以10为增量吗?所以有
=0.9 * (1/1000000 +10000001 +... + 1/88888888)
到此你有何感想,我反正想到了:
=0.9 * search_7()

所以要算:s0[9]和s0[8],只要算一次search_7()
s0[8]=0.9*search_7();    //如果精度不太高的要求,还可以往前推(比如推到search6需要75ms)。
s0[9]=0.9*s0[8] ;     
---------------------------------------------------------
注意:不要用ln(10000008 /10000000)来估计ln(10000008/9999999)   这样本身就有误差,还会传递给ln(1+x)=x,误差更大。
---------------------------------------------------------
差不多了,我也没什么更好的办法了,此事,我可以安心结束了。
  1. #include <stdio.h>
  2. #include <time.h>

  3. void disp(double s0,double s9,int n)
  4. {
  5.     printf( "s0[%d] = %.6f\ns9[%d] = %.6f\ns0/s9 = %.6f\n\n\n", n,s0,n,s9,s0/s9);
  6. }

  7. double calcS(int n)//n=1,2,3,...,
  8. {
  9.     int e[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
  10.     int k;
  11.     double s=0.0;
  12.     for(k=e[n-1];k<e[n];k++)
  13.         s+=1.0/k;
  14.     return s;
  15. }

  16. //------------------------------
  17. double search_1()
  18. {
  19.     double s9,s0=0.0;
  20.     int k;
  21.     for (k=1;k<=8;k++)
  22.         s0+=1.0/k;
  23.     return s0;

  24. }

  25. double search_2()
  26. {
  27.     double s9,s0=0.0;
  28.     int a,b,k=10;
  29.     for (b=1;b<=8;b++,k+=1)
  30.         for (a=0;a<=8;a++,k++)
  31.             s0+=1.0/k;
  32.     return s0;

  33. }

  34. double search_3()
  35. {
  36.     double s9,s0=0.0;
  37.     int a,b,c,k=100;
  38.     for (c=1;c<=8;c++,k+=10)
  39.         for (b=0;b<=8;b++,k+=1)
  40.             for (a=0;a<=8;a++,k++)
  41.                 s0+=1.0/k;
  42.     return s0;

  43. }

  44. double search_4()
  45. {
  46.     double s9,s0=0.0;
  47.     int a,b,c,d,k=1000;
  48.     for (d=1;d<=8;d++,k+=100)
  49.         for (c=0;c<=8;c++,k+=10)
  50.             for (b=0;b<=8;b++,k+=1)
  51.                 for (a=0;a<=8;a++,k++)
  52.                     s0+=1.0/k;
  53.     return s0;

  54. }

  55. double search_5()
  56. {
  57.     double s9,s0=0.0;
  58.     int a,b,c,d,e,k=10000;
  59.     for (e=1;e<=8;e++,k+=1000)
  60.         for (d=0;d<=8;d++,k+=100)
  61.             for (c=0;c<=8;c++,k+=10)
  62.                 for (b=0;b<=8;b++,k+=1)
  63.                     for (a=0;a<=8;a++,k++)
  64.                         s0+=1.0/k;
  65.     return s0;

  66. }

  67. double search_6()
  68. {
  69.     double s9,s0=0.0;
  70.     int a,b,c,d,e,f,k=100000;
  71.     for (f=1;f<=8;f++,k+=10000)
  72.         for (e=0;e<=8;e++,k+=1000)
  73.             for (d=0;d<=8;d++,k+=100)
  74.                 for (c=0;c<=8;c++,k+=10)
  75.                     for (b=0;b<=8;b++,k+=1)
  76.                         for (a=0;a<=8;a++,k++)
  77.                             s0+=1.0/k;
  78.     return s0;

  79. }

  80. double search_7()
  81. {
  82.     double s9,s0=0.0;
  83.     int a,b,c,d,e,f,g,k=1000000;
  84.     for (g=1;g<=8;g++,k+=100000)
  85.         for (f=0;f<=8;f++,k+=10000)
  86.             for (e=0;e<=8;e++,k+=1000)
  87.                 for (d=0;d<=8;d++,k+=100)
  88.                     for (c=0;c<=8;c++,k+=10)
  89.                         for (b=0;b<=8;b++,k+=1)
  90.                             for (a=0;a<=8;a++,k++)
  91.                                 s0+=1.0/k;
  92.      return s0;

  93. }
  94. //下面的可以省了哦,^_^,哈哈
  95. //---------------------------
  96. /*double search_8()
  97. {
  98.     double s9,s0=0.0;
  99.     int a,b,c,d,e,f,g,h,k=10000000;
  100.     for (h=1;h<=8;h++,k+=1000000)
  101.         for (g=0;g<=8;g++,k+=100000)
  102.             for (f=0;f<=8;f++,k+=10000)
  103.                 for (e=0;e<=8;e++,k+=1000)
  104.                     for (d=0;d<=8;d++,k+=100)
  105.                         for (c=0;c<=8;c++,k+=10)
  106.                             for (b=0;b<=8;b++,k+=1)
  107.                                 for (a=0;a<=8;a++,k++)
  108.                                     s0+=1.0/k;
  109.    return s0;

  110. }*/

  111. /*double search_9()
  112. {
  113.     double s9,s0=0.0;
  114.     int a,b,c,d,e,f,g,h,i,k=100000000;
  115.     for (i=1;i<=8;i++,k+=10000000)
  116.         for (h=0;h<=8;h++,k+=1000000)
  117.             for (g=0;g<=8;g++,k+=100000)
  118.                 for (f=0;f<=8;f++,k+=10000)
  119.                     for (e=0;e<=8;e++,k+=1000)
  120.                         for (d=0;d<=8;d++,k+=100)
  121.                             for (c=0;c<=8;c++,k+=10)
  122.                                 for (b=0;b<=8;b++,k+=1)
  123.                                     for (a=0;a<=8;a++,k++)
  124.                                         s0+=1.0/k;
  125.    return s0;

  126. }
  127. */
  128. //----------------------
  129. int main()
  130. {
  131.     double  s0[10]={0};
  132.     double  s9[10]={0};
  133.     //由欧拉公式lim(1+1/2+...+1/n)=lnn+C  (n->无穷,c为常数)
  134.     //从第n=8开始,n值以达到其极限的精度要求
  135.     //完全可以用估计式ln( n/m )=1/n +1/(n-1)+...+1/(m+1)
  136.     //这样明显减少计算时间
  137.     double  s_8=2.3025851829940506340183244547094;
  138.     double  s_9=2.3025851019940457335179917876844;

  139.     double  t0=clock();

  140.     s0[1]=search_1();
  141.     s0[2]=search_2();
  142.     s0[3]=search_3();
  143.     s0[4]=search_4();
  144.     s0[5]=search_5();
  145.     s0[6]=search_6();
  146.     s0[7]=search_7();//如果想得到更粗糙一点的近似值时,可以用s0[7]=0.9*s0[6];输出前几位
  147.     s0[8]=0.9*s0[7];//search_8();
  148.     s0[9]=0.9*s0[8];//search_9();
  149.    

  150.             
  151.     s9[1]=calcS(1)-s0[1];
  152.     disp(s0[1],s9[1],1);
  153.     s9[2]=calcS(2)-s0[2];
  154.     disp(s0[2],s9[2],2);  
  155.     s9[3]=calcS(3)-s0[3];
  156.     disp(s0[3],s9[3],3);
  157.     s9[4]=calcS(4)-s0[4];
  158.     disp(s0[4],s9[4],4);
  159.     s9[5]=calcS(5)-s0[5];
  160.     disp(s0[5],s9[5],5);  
  161.     s9[6]=calcS(6)-s0[6];
  162.     disp(s0[6],s9[6],6);
  163.     s9[7]=calcS(7)-s0[7];
  164.     disp(s0[7],s9[7],7);            
  165.     //==================     
  166.     s9[8]=s_8-s0[8];
  167.     disp(s0[8],s9[8],8);
  168.     s9[9]=s_9-s0[9];   
  169.     disp(s0[9],s9[9],9);
  170.             
  171.     printf("Elapsed time: %f s\n",(clock()-t0)/CLOCKS_PER_SEC);
  172.     system("Pause");
  173.     return 0;
  174. }
复制代码
部分结果:
110.jpg

评分

参与人数 1威望 +3 鲜花 +3 收起 理由
gxqcn + 3 + 3 精彩,妙!

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-12-1 21:01:36 | 显示全部楼层
92# G-Spider
\(^o^)/~,优化无极限啊。看截图你的win7 DPI比较高
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2013-11-4 16:23:52 | 显示全部楼层
本帖最后由 chyanog 于 2013-11-4 16:37 编辑

又写了两个Mathematica版,第一个算9位的需要比较大的内存(2G内存不够);第二个接近了C的速度,算法和86楼的一致,不同的是只算不含9的数,如果把86楼的calcS去掉(这样也只算不含9的),速度几乎一致,注意:需要Mathematica8或以上版本且有Mathematica能识别的C编译器

  1. f[n_] := 1/N@Flatten@Outer[Plus, ##] & @@ Array[10^(n - #) Range[Boole[# == 1], 8] &, n] // Tr;
  2. h[n_] := H[10^n - 1.0] - H[10^(n - 1) - 1.0] /. H -> HarmonicNumber
  3. Table[{Framed@n, h@n - #, #} &@f@n, {n, 8}] // Grid // AbsoluteTiming
复制代码

2013-11-04_161850.png
  1. len = 9;
  2. f1[n_] :=  Array[{Unique["x"], Boole[# == 1], 8} &, n] /.
  3.       it_ :> {1/FromDigits[First /@ it], it} /. {e_, {it__}} :> Hold@Sum[e, it]

  4. cf = Join @@ Table[f1[n], {n, len}] /.
  5.      Hold[x__] :>   Compile[{}, {x}, RuntimeOptions -> "Speed",  CompilationTarget -> "C"];

  6. h[n_] := H[10^n - 1.0] - H[10^(n - 1) - 1.0] /. H -> HarmonicNumber

  7. MapIndexed[{Framed @@ #2, #} &,  Thread@{Array[h, len] - #, #} &@cf[]] // Grid // AbsoluteTiming
复制代码
2013-11-04_161928.png


评分

参与人数 1威望 +3 经验 +3 鲜花 +3 收起 理由
wayne + 3 + 3 + 3 赞一个!

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

GMT+8, 2024-5-3 22:38 , Processed in 0.069232 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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