Commit d0ace313 authored by Boris Mühmer's avatar Boris Mühmer
Browse files

added factorial and binominal coefficient

parent 7e465fd5
Loading
Loading
Loading
Loading

numeric/numeric.go

0 → 100644
+67 −0
Original line number Diff line number Diff line
package numeric

// Factorial calculates n!.
func Factorial(n uint64) uint64 {
	if n < uint64(len(facsSmall)) {
		return factorialSmall(n)
	}
	return factorialCalc(n)
}

// Helpers...
var (
	facsSmall = []struct {
		n uint64
		f uint64
	}{
		{n: 0, f: 1},
		{n: 1, f: 1},
		{n: 2, f: 2},
		{n: 3, f: 6},
		{n: 4, f: 24},
		{n: 5, f: 120},
		{n: 6, f: 720},
		{n: 7, f: 5040},
		{n: 8, f: 40320},
		{n: 9, f: 362880},
		{n: 10, f: 3628800},
		{n: 11, f: 39916800},
		{n: 12, f: 479001600},
		{n: 13, f: 6227020800},
		{n: 14, f: 87178291200},
		{n: 15, f: 1307674368000},
		{n: 16, f: 20922789888000},
		{n: 17, f: 355687428096000},
		{n: 18, f: 6402373705728000},
		{n: 19, f: 121645100408832000},
		{n: 20, f: 2432902008176640000},
		//{n: 21, f: 51090942171709440000},
	}
)

func factorialSmall(n uint64) uint64 {
	if n < uint64(len(facsSmall)) {
		return facsSmall[int(n)].f
	}
	return 0
}

func factorialCalc(n uint64) uint64 {
	var f uint64 = 1
	for n > 1 {
		f *= n
		n--
	}
	return f
}

// BinomialCoefficient calculates n over k.
func BinomialCoefficient(n, k uint64) uint64 {
	if k == 0 {
		return 1
	}
	if n == k {
		return 1
	}
	return Factorial(n) / (Factorial(k) * Factorial(n-k))
}
+78 −0
Original line number Diff line number Diff line
package numeric

import (
	"testing"
)

func TestFactorial(t *testing.T) {
	for _, tv := range []struct {
		n uint64
		f uint64
	}{
		{n: 0, f: 1},
		{n: 1, f: 1},
		{n: 2, f: 2},
		{n: 3, f: 6},
		{n: 4, f: 24},
		{n: 5, f: 120},
		{n: 6, f: 720},
		{n: 7, f: 5040},
		{n: 8, f: 40320},
		{n: 9, f: 362880},
		{n: 10, f: 3628800},
		{n: 11, f: 39916800},
		{n: 12, f: 479001600},
		{n: 13, f: 6227020800},
		{n: 14, f: 87178291200},
		{n: 15, f: 1307674368000},
		{n: 16, f: 20922789888000},
		{n: 17, f: 355687428096000},
		{n: 18, f: 6402373705728000},
		{n: 19, f: 121645100408832000},
		{n: 20, f: 2432902008176640000},
		//{n: 21, f: 51090942171709440000},
	} {
		if f := Factorial(tv.n); f != tv.f {
			t.Errorf("Factorial(%d) is %d, expected %d", tv.n, f, tv.f)
		}
	}
}

func TestFactorial2(t *testing.T) {
	for n := 20; n < 31; n++ {
		f := Factorial(uint64(n))
		t.Logf("Factorial(%d) is %d", n, f)
	}
}

func TestBinomialCoefficient(t *testing.T) {
	for _, tv := range []struct {
		n, k, bc uint64
	}{
		{n: 0, k: 0, bc: 1},
		{n: 1, k: 0, bc: 1},
		{n: 1, k: 1, bc: 1},
		{n: 2, k: 0, bc: 1},
		{n: 2, k: 1, bc: 2},
		{n: 2, k: 2, bc: 1},
		{n: 3, k: 0, bc: 1},
		{n: 3, k: 1, bc: 3},
		{n: 3, k: 2, bc: 3},
		{n: 3, k: 3, bc: 1},
		{n: 4, k: 0, bc: 1},
		{n: 4, k: 1, bc: 4},
		{n: 4, k: 2, bc: 6},
		{n: 4, k: 3, bc: 4},
		{n: 4, k: 4, bc: 1},
		{n: 5, k: 0, bc: 1},
		{n: 5, k: 1, bc: 5},
		{n: 5, k: 2, bc: 10},
		{n: 5, k: 3, bc: 10},
		{n: 5, k: 4, bc: 5},
		{n: 5, k: 5, bc: 1},
	} {
		if bc := BinomialCoefficient(tv.n, tv.k); bc != tv.bc {
			t.Errorf("BinomialCoefficient(%d, %d) is %d, expected %d", tv.n, tv.k, bc, tv.bc)
		}
	}
}