求大数n!的位数

也是坛里面的问题:

已知正整数 n 求 n!的十进制数共有多少位。

这个 n! 怎么办?

n! 的增长率是很可怕的,比 e^n 还要快,其实就是 O(n^n),当 n 值“较”大时,就不能忍了。这个“较”有多大呢?等后面算完了就知道了。递归算 n!,便是尾递归来说,便是栈展得开,效率也受不了,便是效率受得了,也没地儿放。所以绝对不能去算 n!

但只求位数的话,这比较好解,答案是 fix ( log10(n!) ) + 1,是吧,对数是增长级杀手……

反正我们是为了算 ln(n!),可以从数学上找方法。

由于 ln (ab) = ln(a) + ln(b),那么 ln(n!) 是可以展成一个 n 项加式的,但是……n 项式,每项都要求 ln,不是“很”好……

这里引出 Stirling 公式:

看样子不错,便是 n 值“很”小时,舍掉近似项的准确度也是令人满意的,至少,不会影响到 ln(n!),这是一定的。读者可以验证,这个“很”到多小呢?这个可以在此说明,n 可以小到 1!

所以,通过 Stirling 公式,只用算两次 log10 就解决了。

O(1/n)的系数是 1/12,而且这已是一列阻尼级数的最大振幅了,所以便是当 n = 1 的时候,误差最大不过 1/12,对于计算位数,根本不受影响。

用 Matlab 就两句话:

n = 1 : 1 : 107; ans = fix((n.*log(n/exp(1)) + 0.5*log(2*n*pi)) / log(10)) + 1

就将 1 到 107 这些数的位数都算出来了,耗时瞬间。

C 语言会更快。

如果是算[1...n]的ln(n!)值的话,那么通过查表按序从ln(1)算到ln(n)求和的话,每个n只用算一次,比斯特林快,斯特林法用于算单个ln(n!)无疑是最快的。

你可能感兴趣的:(c,matlab,语言)