2.1 Factorial Function
Truncation error and round-off error can also be occurred in implementing the factorial function.
Sterling’s formula for large value approximation is quite inaccurate, and its use should be discouraged now. Lanczos approximation is much better to use now practically.
= function(x) # do not use for real work situation
naiveFactorial.a # x should be a positive integer.
{ = 1
Result for (i in 1:x) Result = Result*i
return(Result)
}format(naiveFactorial.a(170), digits=22)
## [1] "7.2574156153079941358e+306"
format(prod(1:170), digits=22)
## [1] "7.257415615307999125e+306"
naiveFactorial.a(170) == prod(1:170)
## [1] FALSE
identical(naiveFactorial.a(170), prod(1:170)) # bitwise comparison
## [1] FALSE
all.equal(naiveFactorial.a(170), prod(1:170)) # practically same?
## [1] TRUE
= function(x) # Do not use for real work situation
naiveFactorial.b # x should be a positive integer.
{ = 1
Result for (i in x:1) Result = Result*i
return(Result)
}format(naiveFactorial.b(170), digits=22)
## [1] "7.257415615308004115235e+306"
format(prod(170:1), digits=22)
## [1] "7.257415615307999125e+306"
prod(1:170) == prod(170:1) # TRUE in R 3.5.1
## [1] TRUE
= function(x)
betterFactorial.a # x should be a positive integer.
{ = prod(seq(1, x, 2))*prod(seq(2, x, 2))
Result return(Result)
}format(betterFactorial.a(170), digits=22)
## [1] "7.257415615307999125e+306"
prod(1:170) == betterFactorial.a(170)
## [1] TRUE
Practically fast and precise one.
format(tableFactorial(170), digits=22)
## [1] "7.257415615307999125e+306"
Comparison of testFactorial function and factorial R internal function.
= 1
Start = 170 # maximum value not to be infinity
End = 1e-13 # relative tolerance
RelTol for (i in Start:End) {
= tableFactorial(i)
x1 = factorial(i)
x2 = abs((x1 - x2)/x2) # relative difference
RelDiff if (RelDiff > RelTol) print(paste(i, format(c(x1, x2), digits=22)))
}
## [1] "127 3.012660018457659457086e+213" "127 3.012660018457322778484e+213"
## [1] "132 1.118248651196004340015e+224" "132 1.118248651196143034952e+224"
## [1] "134 1.992942746161518811215e+228" "134 1.992942746161724840246e+228"
## [1] "151 8.627209774233240077712e+264" "151 8.627209774234339096158e+264"
## [1] "153 2.006343905095682317264e+269" "153 2.006343905095905783042e+269"
## [1] "154 3.089769613847350809366e+271" "154 3.089769613847712671816e+271"
## [1] "166 9.003691705778437654600e+297" "166 9.003691705779608680550e+297"
## [1] "170 7.257415615307999125303e+306" "170 7.257415615308882284734e+306"
If you make RelTol more strict, you can see more values. Values from tableFactorial are more precise. In fact, results of R internal function prod are same to tableFactorial function.
for (i in 2:170) if (prod(1:i) != tableFactorial(i)) print(i) # nothing to print