You need to use math/big package. You can implement computation recursively or iteratively. Iterative in most cases will be faster and produce less garbage. On my machine iterative impl works 3.1x faster and allocates 2.9x less garbage.
BenchmarkIterAndRecursive/recursive-6 3000 3891062 ns/op 17181056 B/op 15003 allocs/op
BenchmarkIterAndRecursive/iterative-6 10000 1237597 ns/op 656089 B/op 5172 allocs/op
package main
import (
"fmt"
"log"
"math/big"
"testing"
)
func main() {
fmt.Println(factorial(big.NewInt(5000)))
fmt.Println(factorialIter(5000))
}
func TestIterWorkTheSame(t *testing.T) {
recursive := factorial(big.NewInt(5000))
iterative := factorialIter(5000)
if recursive.Cmp(iterative) != 0 {
log.Fatalf("Invalid computation, \n[%v]\n[%v]", recursive, iterative)
}
}
func BenchmarkIterAndRecursive(b *testing.B) {
b.Run("recursive", func(b2 *testing.B) {
for i := 0; i < b2.N; i++ {
factorial(big.NewInt(5000))
}
})
b.Run("iterative", func(b2 *testing.B) {
for i := 0; i < b2.N; i++ {
factorialIter(5000)
}
})
}
func factorial(x *big.Int) *big.Int {
n := big.NewInt(1)
if x.Cmp(big.NewInt(0)) == 0 {
return n
}
return n.Mul(x, factorial(n.Sub(x, n)))
}
func factorialIter(x int) *big.Int {
result := big.NewInt(1)
for i := 2; i <= x; i++ {
result.Mul(result, big.NewInt(int64(i)))
}
return result
}