diff --git a/container/intsets/sparse.go b/container/intsets/sparse.go index be14d0559..763b38485 100644 --- a/container/intsets/sparse.go +++ b/container/intsets/sparse.go @@ -698,19 +698,44 @@ func (s *Sparse) String() string { return buf.String() } -// BitString returns the set s as a non-empty string of 1s and 0s. -// The ith character is 1 if the set contains i. +// BitString returns the set as a string of 1s and 0s denoting the sum +// of the i'th powers of 2, for each i in s. A radix point, always +// preceded by a digit, appears if the sum is non-integral. +// +// Examples: +// {}.BitString() = "0" +// {4,5}.BitString() = "110000" +// {-3}.BitString() = "0.001" +// {-3,0,4,5}.BitString() = "110001.001" // func (s *Sparse) BitString() string { if s.IsEmpty() { return "0" } - b := make([]byte, s.Max()+1) + + min, max := s.Min(), s.Max() + var nbytes int + if max > 0 { + nbytes = max + } + nbytes++ // zero bit + radix := nbytes + if min < 0 { + nbytes += len(".") - min + } + + b := make([]byte, nbytes) for i := range b { b[i] = '0' } + if radix < nbytes { + b[radix] = '.' + } s.forEach(func(x int) { - b[x] = '1' + if x >= 0 { + x += len(".") + } + b[radix-x] = '1' }) return string(b) } diff --git a/container/intsets/sparse_test.go b/container/intsets/sparse_test.go index 258291af1..bdbb8dfd5 100644 --- a/container/intsets/sparse_test.go +++ b/container/intsets/sparse_test.go @@ -23,9 +23,6 @@ func TestBasics(t *testing.T) { if s := s.String(); s != "{}" { t.Errorf("String({}): got %q, want \"{}\"", s) } - if s := s.BitString(); s != "0" { - t.Errorf("BitString({}): got %q, want \"0\"", s) - } if s.Has(3) { t.Errorf("Has(3): got true, want false") } @@ -421,13 +418,24 @@ func TestIntersectionWith(t *testing.T) { } func TestBitString(t *testing.T) { - var set intsets.Sparse - set.Insert(0) - set.Insert(7) - set.Insert(177) - want := "10000001" + strings.Repeat("0", 169) + "1" - if got := set.BitString(); got != want { - t.Errorf("BitString: got %s, want %s", got, want) + for _, test := range []struct { + input []int + want string + }{ + {nil, "0"}, + {[]int{0}, "1"}, + {[]int{0, 4, 5}, "110001"}, + {[]int{0, 7, 177}, "1" + strings.Repeat("0", 169) + "10000001"}, + {[]int{-3, 0, 4, 5}, "110001.001"}, + {[]int{-3}, "0.001"}, + } { + var set intsets.Sparse + for _, x := range test.input { + set.Insert(x) + } + if got := set.BitString(); got != test.want { + t.Errorf("BitString(%s) = %s, want %s", set.String(), got, test.want) + } } }