math/big: better test coverage, misc. cleanups
Change-Id: I4ce5cee63093d917095bf90f4e11123f7ec0f93c
Reviewed-on: https://go-review.googlesource.com/2964
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 3829770..62a07d6 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -736,7 +736,7 @@
// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
// If it returns true, x is prime with probability 1 - 1/4^n.
-// If it returns false, x is not prime. n must be >0.
+// If it returns false, x is not prime. n must be > 0.
func (x *Int) ProbablyPrime(n int) bool {
if n <= 0 {
panic("non-positive n for ProbablyPrime")
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index 520fcb3..a698e2d 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -621,6 +621,44 @@
}
}
+var bitTests = []nat{
+ nil,
+ {0},
+ {1},
+ {0, 1, 2, 3, 4},
+ {4, 3, 2, 1, 0},
+ {4, 3, 2, 1, 0, 0, 0, 0},
+}
+
+func norm(x nat) nat {
+ i := len(x)
+ for i > 0 && x[i-1] == 0 {
+ i--
+ }
+ return x[:i]
+}
+
+func TestBits(t *testing.T) {
+ for _, test := range bitTests {
+ var z Int
+ z.neg = true
+ got := z.SetBits(test)
+ want := norm(test)
+ if got.abs.cmp(want) != 0 {
+ t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want)
+ }
+
+ if got.neg {
+ t.Errorf("SetBits(%v): got negative result")
+ }
+
+ bits := nat(z.Bits())
+ if bits.cmp(want) != 0 {
+ t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want)
+ }
+ }
+}
+
func checkSetBytes(b []byte) bool {
hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
hex2 := hex.EncodeToString(b)
@@ -962,6 +1000,8 @@
}
var composites = []string{
+ "0",
+ "1",
"21284175091214687912771199898307297748211672914763848041968395774954376176754",
"6084766654921918907427900243509372380954290099172559290432744450051395395951",
"84594350493221918389213352992032324280367711247940675652888030554255915464401",
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 6e65ea1..bf00b88 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -610,7 +610,7 @@
const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
func hexValue(ch rune) Word {
- d := int(MaxBase + 1) // illegal base
+ d := int(MaxBase + 1) // invalid base
switch {
case '0' <= ch && ch <= '9':
d = int(ch - '0')
@@ -634,9 +634,9 @@
// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
//
func (z nat) scan(r io.RuneScanner, base int) (nat, int, error) {
- // reject illegal bases
+ // reject invalid bases
if base < 0 || base == 1 || MaxBase < base {
- return z, 0, errors.New("illegal number base")
+ return z, 0, errors.New("invalid number base")
}
// one char look-ahead
@@ -728,7 +728,13 @@
// decimalString returns a decimal representation of x.
// It calls x.string with the charset "0123456789".
func (x nat) decimalString() string {
- return x.string(lowercaseDigits[0:10])
+ return x.string(lowercaseDigits[:10])
+}
+
+// hexString returns a hexadecimal representation of x.
+// It calls x.string with the charset "0123456789abcdef".
+func (x nat) hexString() string {
+ return x.string(lowercaseDigits[:16])
}
// string converts x to a string using digits from a charset; a digit with
@@ -739,8 +745,8 @@
// special cases
switch {
- case b < 2 || MaxBase > 256:
- panic("illegal base")
+ case b < 2 || b > 256:
+ panic("invalid character set length")
case len(x) == 0:
return string(charset[0])
}
diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go
index 5d93df7..acd265b 100644
--- a/src/math/big/nat_test.go
+++ b/src/math/big/nat_test.go
@@ -243,16 +243,28 @@
{nil, "01", "0"},
{nat{1}, "01", "1"},
{nat{0xc5}, "01", "11000101"},
- {nat{03271}, lowercaseDigits[0:8], "3271"},
- {nat{10}, lowercaseDigits[0:10], "10"},
- {nat{1234567890}, uppercaseDigits[0:10], "1234567890"},
- {nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"},
- {nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"},
- {nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"},
- {nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"},
+ {nat{03271}, lowercaseDigits[:8], "3271"},
+ {nat{10}, lowercaseDigits[:10], "10"},
+ {nat{1234567890}, uppercaseDigits[:10], "1234567890"},
+ {nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"},
+ {nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"},
+ {nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"},
+ {nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"},
}
func TestString(t *testing.T) {
+ // test invalid character set explicitly
+ var panicStr string
+ func() {
+ defer func() {
+ panicStr = recover().(string)
+ }()
+ natOne.string("0")
+ }()
+ if panicStr != "invalid character set length" {
+ t.Errorf("expected panic for invalid character set")
+ }
+
for _, a := range strTests {
s := a.x.string(a.c)
if s != a.s {
@@ -474,8 +486,8 @@
z = z.expWW(x, y)
var s string
- s = z.string(lowercaseDigits[0:base])
- if t := toString(z, lowercaseDigits[0:base]); t != s {
+ s = z.string(lowercaseDigits[:base])
+ if t := toString(z, lowercaseDigits[:base]); t != s {
b.Fatalf("scanning: got %s; want %s", s, t)
}
b.StartTimer()
@@ -513,11 +525,11 @@
b.StopTimer()
var z nat
z = z.expWW(x, y)
- z.string(lowercaseDigits[0:base]) // warm divisor cache
+ z.string(lowercaseDigits[:base]) // warm divisor cache
b.StartTimer()
for i := 0; i < b.N; i++ {
- _ = z.string(lowercaseDigits[0:base])
+ _ = z.string(lowercaseDigits[:base])
}
}
@@ -551,12 +563,12 @@
for d := 1; d <= 10000; d *= 10 {
b.StopTimer()
var z nat
- z = z.expWW(base, Word(d)) // build target number
- _ = z.string(lowercaseDigits[0:base]) // warm divisor cache
+ z = z.expWW(base, Word(d)) // build target number
+ _ = z.string(lowercaseDigits[:base]) // warm divisor cache
b.StartTimer()
for i := 0; i < b.N; i++ {
- _ = z.string(lowercaseDigits[0:base])
+ _ = z.string(lowercaseDigits[:base])
}
}
@@ -581,8 +593,8 @@
for b = 2; b <= 16; b++ {
for p = 0; p <= 512; p++ {
x := nat(nil).expWW(b, p)
- xs := x.string(lowercaseDigits[0:b])
- xs2 := toString(x, lowercaseDigits[0:b])
+ xs := x.string(lowercaseDigits[:b])
+ xs2 := toString(x, lowercaseDigits[:b])
if xs != xs2 {
t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
}
@@ -691,20 +703,30 @@
}
func TestTrailingZeroBits(t *testing.T) {
+ // test 0 case explicitly
+ if n := trailingZeroBits(0); n != 0 {
+ t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
+ }
+
x := Word(1)
- for i := uint(0); i <= _W; i++ {
+ for i := uint(0); i < _W; i++ {
n := trailingZeroBits(x)
- if n != i%_W {
+ if n != i {
t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
}
x <<= 1
}
+ // test 0 case explicitly
+ if n := nat(nil).trailingZeroBits(); n != 0 {
+ t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
+ }
+
y := nat(nil).set(natOne)
for i := uint(0); i <= 3*_W; i++ {
n := y.trailingZeroBits()
if n != i {
- t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.string(lowercaseDigits[0:16]), n, i)
+ t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
}
y = y.shl(y, 1)
}