1000 的阶乘有几位数? - 后续, 求解

这是在 2006 年 11 月 17 日浏览小百合时得到的,当时上不来,就暂存在我的信箱里了。

南京大学小百合站,Algorithm 版,x->18->1 和 x->18-2。

x->18->1:(两处红色标记是我个人加上的,怀疑原文有误,即若有 10 和 100,则前面不应有 90 和 1800)
令结果为 x
x=log2+log3+...+log9
  +90+log1.1+log1.2+...+log9.9
  +1800+log1.01+log1.02+...+log9.99
  +3
 =∫logx dx (从2到10)
  +90+10∫logx dx(从1.1到9.9)
  +1800+ 100∫logx dx (从1.01到9.99)
  +3
 = ...
后两次积分上限的不同是考虑到修正

x->18->2:
x=(∫log(x)dx(2--1001)+∫log(x)dx(1--1000))/2
 =((x*log(x)-∫xdlog(x))(2--1001)+(x*log(x)-∫xdlog(x))(1---1000))/2
 =2567.857000.....


我个人的想法:

经过上述两个方法,我猜想求解一个数的位数可以求解该数对其基数的对数(此处是以 10 为基数的),找了几个数写了写,发现可以:
一个以 b 为基数的数 N,在以 b 为基数的计数系统中的位数 l,可以通过求 N 对 b 的对数求得。
具体为:l=floor[log b (N) + 1],即求对数,结果加 1 后向下取整。
例如:
  • length(123456789)10=floor[lg(123456789)+1]=floor[8.091514977+1 ]=9
  • length(100000000)10=floor[lg(100000000)+1]=floor[8+1]=9
  • length(10101)2=floor[log 2 (23) + 1]=floor[4.523561956+1]=5  (10101)2=(23)10
再回到求解 1000 的阶乘的位数上,则根据上面的说明,有:(设 1000 的阶乘结果为 N)
length(N)10=floor[lg(N)+1]
           =floor[lg(1*2*3*...*999*1000)+1]
           =floor[lg1+lg2+lg3+...+lg999+lg1000+1]
           =floor[lg2+lg3+...lg999+lg1000+1]    <= lg1=0
这时问题转到了求解 lg2+lg3+...+lg999+lg1000 的累加上面。

对于这一方面我不是很清楚(高等数学基本都不记得了...),不过根据前面两篇文章,好像有:
∑(N=2..1000)lgN = ∫lgxdx (x=2..1000)

如果成立的话,则根据 lgx = lnx/ln10 有:
∫lgxdx (x=2..1000) = (1/ln10)*∫lnxdx (x=2..1000)
                   = (1/ln10)*[x*lnx - ∫xd(lnx)] (x=2..1000)
                   = (1/ln10)*[x*lnx - ∫dx] (x=2..1000)
                   = (1/ln10)*[x*lnx - x] (x=2..1000)
                   = x*(lnx - 1)/ln10 (x=2..1000)

然后由牛顿-莱伯尼茨公式可以得到:(也不知道是否能在此处应用...)
∫lgxdx (x=2..1000) = 1000*(ln1000 - 1)/ln10 - 2*(ln2 - 1)/ln10
                   = [1000*(6.907755279 - 1) - 2*(0.693147181 - 1)]/ln10
                   = [1000* 5.907755279 - 2*(-0.306852819)]/2.302585093
                   = [5907.755279 - (- 0.613705639)]/2.302585093
                   = 5908.368984639/2.302585093
                   = 2565.97204707

将结果代回前面的式子:
length(N)10 = floor[2565.97204707 + 1] = 2566

原先通过 Python 计算过 1000 的阶乘,位数为 2568 位。

考虑前面推算的过程中把 x=1 时 lg1 略掉了,理论上不应产生区别,但若要是不略掉该项时,则结果变成:
∫lgxdx (x=2..1000) = 1000*(ln1000 - 1)/ln10 - 1*(ln1 - 1)/ln10
                   = [1000*( 6.907755279 - 1) - 1*(0 - 1)]/ln10
                   = [1000*5.907755279 - 1*(-1)]/2.302585093
                   = [5907.755279 + 1]/2.302585093
                   = 5908.755279/2.302585093
                   = 2566.13981258

length(N)10 = floor[2566.13981258 + 1] = 2567

可见结果略有不同,但都与正确结果有一点小偏差,个人认为思路是正确的,方法还有待改进。同时看到第二篇引文的结果非常接近,不过我还不理解,还需在琢磨琢磨。

还要再好好看看高等数学...


posted on 2007-01-11 12:14 ScorpioLove 阅读(1261) 评论(4)  编辑 收藏 所属分类: 数据结构与算法
 
把求lgN(N=2.3.4....1000)转换为积分,这个思路就有误差吧。
积分是连续的,而这里的N是离散的,所以这里的转换不合理。
Posted @ 2007-04-18 09:25    回复  引用  查看    
#2楼 
你红字加的内容不对,不应该乘10和100;
楼上的说的也不对,把不可直接求职的离散转为积分是基本的方法,只要误差允许接受就可以,具体可以看CLRS的附录A
Posted @ 2007-04-24 10:07    回复  引用  查看    
#3楼 [楼主]
谢谢各位回复,同时希望能原谅我不能及时的回复各位。

@ 蔡晖

事实上这个问题,我在计算前也考虑过,确实有误差,不过就像 wqx 说的,只要误差可接受就可以了,像这里的误差相对于实际结果而言是比较小的,可以接受。

@ wqx

关于红字部分,我在算式前面的括号里注明了,10 和 100 是原来算式里就有的,但我觉得不该加,所以就用红色标记了一下,可能导致你误以为是我强调要加上的...

关于 CLRS,我目前正在读,不过感觉好难啊,好多课后题都不会...
如果可能,希望能和你交流一下^_^。
Posted @ 2007-04-24 13:26    回复  引用  查看    
#4楼 
居然看到了牛顿莱布尼茨公式。。。。。
Posted @ 2007-09-18 17:53    回复  引用  查看   
posted on 2008-06-26 14:22 c++ 学习 阅读(1656) 评论(0)  编辑 收藏 引用 所属分类: 算法
 

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理