<br>
斯特林公式(Stirling's approximation 或 Stirling's formula)是一个用于近似计算阶乘(n!)的公式。当要为某些极大的 n 求阶乘时,直接计算 n!的计算量会随着 n 的增大而快速增长,导致计算变得不实际,尤其是在计算机程序中。斯特林公式提供了一种有效的方式来近似这种大数的阶乘,能够将求解阶乘的复杂度降低到对数级。
公式如下:
[
]
其中,(e)是自然对数的底数(约等于 2.71828),(π)是圆周率。
<font size=1 color=red>
斯特林是一位苏格兰数学家,生活在大概清朝康雍乾时期. 不是现在在英超踢快乐足球的那位
但实际上这个公式最早是棣莫弗发现的,就是提出概率论中棣莫弗-拉普拉斯中心极限定理的那位,法国裔英国籍的数学家
更多可参考:
大数定律与中心极限定理
揭示函数渐近展开之奥秘——棣莫弗-拉普拉斯定理的应用与实践
</font>
<br>
作用
<br>
斯特林公式在数学、物理学、工程学和计算机科学等领域有广泛的应用,主要用于:
<br>
使用 Go 代码验证斯特林公式的准确性
如下编写一个简单的 Go 程序来计算斯特林公式的近似值,并与实际的阶乘值进行比较,以此来验证斯特林公式的准确性
<br>
package main
import (
"fmt"
"math"
)
// 计算阶乘 n!
func factorial(n int64) int64 {
if n == 0 {
return 1
}
return n * factorial(n-1)
}
// 斯特林公式近似计算 n!
func stirlingApproximation(n float64) float64 {
return math.Sqrt(2*math.Pi*n) * math.Pow(n/math.E, n)
}
func main() {
var a int64 = 5 // 示例:计算5!
exact := factorial(a)
approx := stirlingApproximation(float64(a))
fmt.Printf("Exact factorial of %d is: %d\n", a, exact)
fmt.Printf("Stirling's approximation of %d is: %f\n", a, approx)
fmt.Printf("Difference: %f\n", math.Abs(float64(exact)-approx))
fmt.Printf("误差率: %f\n", math.Abs(float64(exact)-approx)/float64(exact))
fmt.Println()
var b int64 = 10 // 示例:计算10!
exact = factorial(b)
approx = stirlingApproximation(float64(b))
fmt.Printf("Exact factorial of %d is: %d\n", b, exact)
fmt.Printf("Stirling's approximation of %d is: %f\n", b, approx)
fmt.Printf("Difference: %f\n", math.Abs(float64(exact)-approx))
fmt.Printf("误差率: %f\n", math.Abs(float64(exact)-approx)/float64(exact))
fmt.Println()
var c int64 = 20 // 示例:计算20!
exact = factorial(c)
approx = stirlingApproximation(float64(c))
fmt.Printf("Exact factorial of %d is: %d\n", c, exact)
fmt.Printf("Stirling's approximation of %d is: %f\n", c, approx)
fmt.Printf("Difference: %f\n", math.Abs(float64(exact)-approx))
fmt.Printf("误差率: %f\n", math.Abs(float64(exact)-approx)/float64(exact))
}
复制代码
在线运行
输出:
Exact factorial of 5 is: 120
Stirling's approximation of 5 is: 118.019168
Difference: 1.980832
误差率: 0.016507
Exact factorial of 10 is: 3628800
Stirling's approximation of 10 is: 3598695.618741
Difference: 30104.381259
误差率: 0.008296
Exact factorial of 20 is: 2432902008176640000
Stirling's approximation of 20 is: 2422786846761136640.000000
Difference: 10115161415503360.000000
误差率: 0.004158
复制代码
上面程序中,factorial
函数递归地计算了一个数的阶乘,而stirlingApproximation
函数则根据斯特林公式计算了阶乘的近似值。通过比较两者的结果,可以看到斯特林公式给出的近似值与实际阶乘值之间的差异。
看起来,n 越大,斯特林公式计算的结果,和实际 n 的阶乘值之间的误差会越小。在实际应用中,通常只用斯特林公式来近似计算大数的阶乘。
如果对于非常大的n
值,直接计算阶乘可能会导致整数溢出。
2 的 64 次方: 922337203685477580720 的阶乘: 2432902008176640000
<br>
如果 n=21,就会超出 int64 的范围了,需要使用 bigint
如下:
package main
import (
"fmt"
"math"
"math/big"
)
func factorial(n int) *big.Int {
bigN := big.NewInt(int64(n))
if n == 0 {
return big.NewInt(1)
}
result := big.NewInt(1)
for i := big.NewInt(2); i.Cmp(bigN) <= 0; i.Add(i, big.NewInt(1)) {
result.Mul(result, i)
}
return result
}
func stirlingApproximation(n float64) float64 {
return math.Sqrt(2*math.Pi*n) * math.Pow(n/math.E, n)
}
func main() {
var x = 50
exact := factorial(x)
approx := stirlingApproximation(float64(x))
fmt.Println("Exact factorial of 50 is: ", exact.String())
fmt.Printf("Stirling's approximation of 50 is: %f\n", approx)
floatExact, _ := exact.Float64()
fmt.Printf("Difference: %f\n", approx-floatExact)
fmt.Printf("误差率: %f\n", math.Abs(floatExact-approx)/floatExact)
fmt.Println()
fmt.Println()
var y = 100
exact = factorial(y)
approx = stirlingApproximation(float64(y))
fmt.Println("Exact factorial of 100 is: ", exact.String())
fmt.Printf("Stirling's approximation of 100 is: %f\n", approx)
floatExact, _ = exact.Float64()
fmt.Printf("Difference: %f\n", approx-floatExact)
fmt.Printf("误差率: %f\n", math.Abs(floatExact-approx)/floatExact)
fmt.Println()
fmt.Println()
var z = 150
exact = factorial(z)
approx = stirlingApproximation(float64(z))
fmt.Println("Exact factorial of 150 is: ", exact.String())
fmt.Printf("Stirling's approximation of 150 is: %f\n", approx)
floatExact, _ = exact.Float64()
fmt.Printf("Difference: %f\n", approx-floatExact)
fmt.Printf("误差率: %f\n", math.Abs(floatExact-approx)/floatExact)
}
复制代码
输出:
Exact factorial of 50 is: 30414093201713378043612608166064768844377641568960512000000000000
Stirling's approximation of 50 is: 30363445939381662539822092816663010554176972669373577771666636800.000000
Difference: -50647262331712294376073382985838127571388053403738488862408704.000000
误差率: 0.001665
Exact factorial of 100 is: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Stirling's approximation of 100 is: 93248476252694086082741480126603978924814282139093327106422842133464418571195672826024908864958629150354343629008809013568909876278442701697442603499744395264.000000
Difference: -77739191250067288427407758913009195131184458378162476302178214323666797065713990911211707211836434286969363646771402787323207418418652286983705207165157376.000000
误差率: 0.000833
Exact factorial of 150 is: 57133839564458545904789328652610540031895535786011264182548375833179829124845398393126574488675311145377107878746854204162666250198684504466355949195922066574942592095735778929325357290444962472405416790722118445437122269675520000000000000000000000000000000000000
Stirling's approximation of 150 is: 57102107404794002531486784484402246707941441176612129409152808169561298568174402178138464969562539359822454467015048872053054189489998393451341243701758138113713430727594194645443385915763391969083296804782229203527249066910085527728440667512127808337057891221504.000000
Difference: -31732159664543345709716527525897500549797926077936066874981976179631513538039613253514105887862044104270936341040554986498420072620437122053086846109932370973210446316192698228766975256370780291479993145852823806527483089444575765382819081148258251866386726912.000000
误差率: 0.000555
复制代码
<br>
「阶乘秘方」斯特林公式:计算大数阶乘的神奇逼近算法
评论