Commit 919a6fbe authored by Robert Griesemer's avatar Robert Griesemer

math/big: faster Int.Binomial(n, k) for k > n/2

benchmark             old ns/op     new ns/op     delta
BenchmarkBinomial     478664        4410          -99.08%

Fixes #10084.

Change-Id: Ib75034428e32c79c9a660ae9f9bd396afc6a7f11
Reviewed-on: https://go-review.googlesource.com/8351Reviewed-by: 's avatarAlan Donovan <adonovan@google.com>
parent 3ed9e4ca
......@@ -184,6 +184,10 @@ func (z *Int) MulRange(a, b int64) *Int {
// Binomial sets z to the binomial coefficient of (n, k) and returns z.
func (z *Int) Binomial(n, k int64) *Int {
// reduce the number of multiplications by reducing k
if n/2 < k && k <= n {
k = n - k // Binomial(n, k) == Binomial(n, n-k)
}
var a, b Int
a.MulRange(n-k+1, n)
b.MulRange(1, k)
......
......@@ -219,6 +219,45 @@ func TestMulRangeZ(t *testing.T) {
}
}
func TestBinomial(t *testing.T) {
var z Int
for _, test := range []struct {
n, k int64
want string
}{
{0, 0, "1"},
{0, 1, "0"},
{1, 0, "1"},
{1, 1, "1"},
{1, 10, "0"},
{4, 0, "1"},
{4, 1, "4"},
{4, 2, "6"},
{4, 3, "4"},
{4, 4, "1"},
{10, 1, "10"},
{10, 9, "10"},
{10, 5, "252"},
{11, 5, "462"},
{11, 6, "462"},
{100, 10, "17310309456440"},
{100, 90, "17310309456440"},
{1000, 10, "263409560461970212832400"},
{1000, 990, "263409560461970212832400"},
} {
if got := z.Binomial(test.n, test.k).String(); got != test.want {
t.Errorf("Binomial(%d, %d) = %s; want %s", test.n, test.k, got, test.want)
}
}
}
func BenchmarkBinomial(b *testing.B) {
var z Int
for i := b.N - 1; i >= 0; i-- {
z.Binomial(1000, 990)
}
}
// Examples from the Go Language Spec, section "Arithmetic operators"
var divisionSignsTests = []struct {
x, y int64
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment