func (ps *Swing) OddSwing(z *big.Int, k uint) *big.Int { if k < uint(len(SmallOddSwing)) { return z.SetInt64(SmallOddSwing[k]) } rootK := xmath.FloorSqrt(k) ps.factors = ps.factors[:0] // reset length, reusing existing capacity ps.Sieve.Iterate(3, uint64(rootK), func(p uint64) (terminate bool) { q := uint64(k) / p for q > 0 { if q&1 == 1 { ps.factors = append(ps.factors, p) } q /= p } return }) ps.Sieve.Iterate(uint64(rootK+1), uint64(k/3), func(p uint64) (term bool) { if (uint64(k) / p & 1) == 1 { ps.factors = append(ps.factors, p) } return }) ps.Sieve.Iterate(uint64(k/2+1), uint64(k), func(p uint64) (term bool) { ps.factors = append(ps.factors, p) return }) return xmath.Product(z, ps.factors) }
// 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) }
func TestFloorSqrt(t *testing.T) { tcs := []struct { n, s uint }{ {0, 0}, {1, 1}, {2, 1}, {3, 1}, {4, 2}, {5, 2}, {7, 2}, {1<<20 - 1, 1<<10 - 1}, {1 << 20, 1 << 10}, {1<<20 + 1, 1 << 10}, {math.MaxUint32 - 1, math.MaxUint16}, } for _, tc := range tcs { if s := xmath.FloorSqrt(tc.n); s != tc.s { t.Errorf("FloorSqrt(%d) expected to be %d. got %d", tc.n, tc.s, s) } } }