func TestLog2(t *testing.T) { for _, tc := range s { u := uint(tc) u >>= u & 0x1f if u == 0 { continue // not interesting } l := xmath.Log2(u) s := u >> l if s != 1 { t.Fatalf("Log2(%d) returned %x", u, l) } } }
func init() { // singletons Binary = func(n uint) uint { return n / 2 } CoBinary = func(n uint) uint { return (n + 1) / 2 } Dichotomic = func(n uint) uint { return n / (1 << ((xmath.Log2(n) + 1) / 2)) } // non-singletons Total = func(n uint) []uint { s := make([]uint, n-2) for i := range s { s[i] = uint(i + 2) } // fmt.Printf(indent+" Total(%d) = %v\n", n, s) return s } Dyadic = func(n uint) []uint { s := make([]uint, xmath.Log2(n)-1) for i := range s { s[i] = n / (uint(1) << uint(len(s)-i)) } // fmt.Printf(indent+" Dyadic(%d) = %v\n", n, s) return s } Fermat = func(n uint) []uint { s := make([]uint, 1+xmath.Log2(xmath.Log2(n)-1)) for i := range s { s[i] = n / (uint(1) << (uint(1) << uint(len(s)-1-i))) } // fmt.Printf(indent+" Fermat(%d) = %v\n", n, s) return s } }
// Chain computes an addition chain, returning it in StarChain form. func (γ SingletonStrategy) Chain(n uint) StarChain { // This is the function minChain as described in the paper. switch a := xmath.Log2(n); { case n == 1<<a: r := make(StarChain, a) for i := range r { r[i] = i } return r case n == 3: return StarChain{0, 0} } s, _ := γ.chain1(n, γ(n)) return s }
// Factorial computes n!, leaving result in z and returning z. func Factorial(z *big.Int, n uint) *big.Int { currentN := int64(1) var product func(*big.Int, uint) *big.Int product = func(z *big.Int, n uint) *big.Int { switch n { case 1: currentN += 2 return z.SetInt64(currentN) case 2: currentN += 2 r := currentN currentN += 2 r *= currentN return z.SetInt64(r) } m := n / 2 var r big.Int return z.Mul(product(z, m), product(&r, n-m)) } var p, pr big.Int p.SetInt64(1) z.SetInt64(1) var h, shift uint var high uint = 1 log2n := xmath.Log2(n) for h != n { shift += h h = n >> log2n log2n-- length := high high = (h - 1) | 1 length = (high - length) / 2 if length > 0 { z.Mul(z, p.Mul(&p, product(&pr, length))) } } return z.Lsh(z, shift) }
// minChain returns a chain that is stored in the map. func (cc *cm) minChain(n uint) StarChain { // fmt.Println(indent, "minChain(", n, ")") ns := indent indent += " " defer func() { indent = ns }() if s, ok := cc.m[n]; ok { // fmt.Println(indent, "memoized") return s } // This is the function minChain as described in the paper. switch a := xmath.Log2(n); { case n == 1<<a: r := make(StarChain, a) for i := range r { r[i] = i } cc.m[n] = r // fmt.Println(indent, "It's a power of 2. Returning", r.AddChain()) return r // case n == 3: // // fmt.Println(indent, "It's 3. Returning", StarChain{0, 0}.AddChain()) // return StarChain{0, 0} } min := int(n) var minS StarChain // var bestk uint // fmt.Println(indent, "Considering some possibilities...") for _, k := range cc.γ(n) { s, _ := cc.chain1(n, k) if len(s) < min { // fmt.Println(indent, "oh,", k, "was a good one") // bestk = k min = len(s) minS = s } } cc.m[n] = minS // fmt.Println(indent, "yeah,", bestk, "was best. Returning", minS.AddChain()) return minS }