// BinomialS computes the binomial coefficient C(n,k) using prime number // sieve p. BinomialS returns nil if p is too small. Otherwise it leaves // the result in z, replacing the existing value of z, and returning z. func BinomialS(z *big.Int, p *sieve.Sieve, n, k uint) *big.Int { if uint64(n) > p.Lim { return nil } if k > n { return z.SetInt64(0) } if k > n/2 { k = n - k } if k < 3 { switch k { case 0: return z.SetInt64(1) case 1: return z.SetInt64(int64(n)) case 2: var n1 big.Int return z.Rsh(z.Mul(z.SetInt64(int64(n)), n1.SetInt64(int64(n-1))), 1) } } rootN := uint64(xmath.FloorSqrt(n)) var factors []uint64 p.Iterate(2, rootN, func(p uint64) (terminate bool) { var r, nn, kk uint64 = 0, uint64(n), uint64(k) for nn > 0 { if nn%p < kk%p+r { r = 1 factors = append(factors, p) } else { r = 0 } nn /= p kk /= p } return }) p.Iterate(rootN+1, uint64(n/2), func(p uint64) (terminate bool) { if uint64(n)%p < uint64(k)%p { factors = append(factors, p) } return }) p.Iterate(uint64(n-k+1), uint64(n), func(p uint64) (terminate bool) { factors = append(factors, p) return }) return xmath.Product(z, factors) }
// a few tests on the zero object func TestZero(t *testing.T) { // test Limit() on zero object var s sieve.Sieve n := s.Limit() if n != 0 { t.Error("zero object Limit() = ", n) } // test Iterate succeeds on zero object if !s.Iterate(0, 0, func(uint64) bool { return false }) { t.Error("Iterate fails on zero object") } // test Iterate fails on request > limit if s.Iterate(0, 1, func(uint64) bool { return false }) { t.Error("Iterate attempts request > limit on zero object") } }