From 919a6fbeab6e4eb73c2cca596ca79ae1a2abda34 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 1 Apr 2015 11:49:12 -0700 Subject: [PATCH] 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/8351 Reviewed-by: Alan Donovan --- src/math/big/int.go | 4 ++++ src/math/big/int_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/math/big/int.go b/src/math/big/int.go index 0695d78973..3410ec4729 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go @@ -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) diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go index 058dd96292..a972a7249b 100644 --- a/src/math/big/int_test.go +++ b/src/math/big/int_test.go @@ -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