add choose pkg
This commit is contained in:
parent
f5380ac47a
commit
332d5949c8
21
choose/LICENSE
Normal file
21
choose/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Aaron Cannon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
12
choose/README.md
Normal file
12
choose/README.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# N choose K for Go/Golang
|
||||
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/golang-standards/project-layout?style=flat-square)](https://goreportcard.com/report/github.com/cannona/choose)
|
||||
[![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/cannona/choose)
|
||||
[![Release](https://img.shields.io/github/release/golang-standards/project-layout.svg?style=flat-square)](https://github.com/cannona/choose/releases/latest)
|
||||
|
||||
package choose implements the N choose K formula, or the binomial coefficient formula. See https://en.wikipedia.org/wiki/Binomial_coefficient for more.
|
||||
|
||||
### Installation
|
||||
|
||||
go get github.com/cannona/choose
|
||||
|
32
choose/choose.go
Normal file
32
choose/choose.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2018, Aaron Cannon under the BSD license.
|
||||
// See the license file for details.
|
||||
|
||||
// Package choose implements the N choose K formula, or the binomial coefficient
|
||||
// formula. See https://en.wikipedia.org/wiki/Binomial_coefficient for more.
|
||||
package choose
|
||||
|
||||
// Choose calculates n choose k. Overflows are not detected, and Choose panics
|
||||
// if n >= k >= 0 is violated.
|
||||
func Choose(n, k int64) int64 {
|
||||
if k > n {
|
||||
panic("Choose: k > n")
|
||||
}
|
||||
if k < 0 {
|
||||
panic("Choose: k < 0")
|
||||
}
|
||||
if n <= 1 || k == 0 || n == k {
|
||||
return 1
|
||||
}
|
||||
if newK := n - k; newK < k {
|
||||
k = newK
|
||||
}
|
||||
if k == 1 {
|
||||
return n
|
||||
}
|
||||
// Our return value, and this allows us to skip the first iteration.
|
||||
ret := int64(n - k + 1)
|
||||
for i, j := ret+1, int64(2); j <= k; i, j = i+1, j+1 {
|
||||
ret = ret * i / j
|
||||
}
|
||||
return ret
|
||||
}
|
49
choose/choose_test.go
Normal file
49
choose/choose_test.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package choose
|
||||
|
||||
import "testing"
|
||||
|
||||
func didPanic(f func()) (ret bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ret = true
|
||||
}
|
||||
}()
|
||||
f()
|
||||
return
|
||||
}
|
||||
|
||||
func TestChoose(t *testing.T) {
|
||||
// Let's use Pascal's triangle for the values.
|
||||
row := append([]int64(nil), 1)
|
||||
for n := int64(0); n < 62; n++ {
|
||||
for k, v := range row {
|
||||
if x := Choose(n, int64(k)); x != v {
|
||||
t.Fatalf("%v choose %v returned %v, not %v", n, k, x, v)
|
||||
}
|
||||
}
|
||||
newRow := make([]int64, len(row)+1)
|
||||
newRow[0] = 1
|
||||
for i := 1; i < len(row); i++ {
|
||||
newRow[i] = row[i-1] + row[i]
|
||||
}
|
||||
newRow[len(row)] = 1
|
||||
row = newRow
|
||||
}
|
||||
// Ensure it panics when it should.
|
||||
if !didPanic(func() {
|
||||
Choose(3, 4)
|
||||
}) {
|
||||
t.Fatal("Choose did not panic when k > n.")
|
||||
}
|
||||
if !didPanic(func() {
|
||||
Choose(3, -1)
|
||||
}) {
|
||||
t.Fatal("Choose did not panic when k < 0")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChoose(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Choose(61, 30)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user