math/big: add IsInt64/IsUint64 predicates
Change-Id: Ia5ed3919cb492009ac8f66d175b47a69f83ee4f1
Reviewed-on: https://go-review.googlesource.com/36487
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 1d8dabc..bed8d60 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -324,22 +324,22 @@
return
}
-// low32 returns the least significant 32 bits of z.
-func low32(z nat) uint32 {
- if len(z) == 0 {
+// low32 returns the least significant 32 bits of x.
+func low32(x nat) uint32 {
+ if len(x) == 0 {
return 0
}
- return uint32(z[0])
+ return uint32(x[0])
}
-// low64 returns the least significant 64 bits of z.
-func low64(z nat) uint64 {
- if len(z) == 0 {
+// low64 returns the least significant 64 bits of x.
+func low64(x nat) uint64 {
+ if len(x) == 0 {
return 0
}
- v := uint64(z[0])
- if _W == 32 && len(z) > 1 {
- v |= uint64(z[1]) << 32
+ v := uint64(x[0])
+ if _W == 32 && len(x) > 1 {
+ return uint64(x[1])<<32 | v
}
return v
}
@@ -360,6 +360,20 @@
return low64(x.abs)
}
+// IsInt64 reports whether x can be represented as an int64.
+func (x *Int) IsInt64() bool {
+ if len(x.abs) <= 64/_W {
+ w := int64(low64(x.abs))
+ return w >= 0 || x.neg && w == -w
+ }
+ return false
+}
+
+// IsUint64 reports whether x can be represented as a uint64.
+func (x *Int) IsUint64() bool {
+ return !x.neg && len(x.abs) <= 64/_W
+}
+
// SetString sets z to the value of s, interpreted in the given base,
// and returns z and a boolean indicating success. The entire string
// (not just a prefix) must be valid for success. If SetString fails,
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index b8e0778..155ccee 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -7,8 +7,8 @@
import (
"bytes"
"encoding/hex"
- "fmt"
"math/rand"
+ "strconv"
"strings"
"testing"
"testing/quick"
@@ -903,56 +903,105 @@
}
}
-var int64Tests = []int64{
- 0,
- 1,
- -1,
- 4294967295,
- -4294967295,
- 4294967296,
- -4294967296,
- 9223372036854775807,
- -9223372036854775807,
- -9223372036854775808,
+var int64Tests = []string{
+ // int64
+ "0",
+ "1",
+ "-1",
+ "4294967295",
+ "-4294967295",
+ "4294967296",
+ "-4294967296",
+ "9223372036854775807",
+ "-9223372036854775807",
+ "-9223372036854775808",
+
+ // not int64
+ "0x8000000000000000",
+ "-0x8000000000000001",
+ "38579843757496759476987459679745",
+ "-38579843757496759476987459679745",
}
func TestInt64(t *testing.T) {
- for i, testVal := range int64Tests {
- in := NewInt(testVal)
- out := in.Int64()
+ for _, s := range int64Tests {
+ var x Int
+ _, ok := x.SetString(s, 0)
+ if !ok {
+ t.Errorf("SetString(%s, 0) failed", s)
+ continue
+ }
- if out != testVal {
- t.Errorf("#%d got %d want %d", i, out, testVal)
+ want, err := strconv.ParseInt(s, 0, 64)
+ if err != nil {
+ if err.(*strconv.NumError).Err == strconv.ErrRange {
+ if x.IsInt64() {
+ t.Errorf("IsInt64(%s) succeeded unexpectedly", s)
+ }
+ } else {
+ t.Errorf("ParseInt(%s) failed", s)
+ }
+ continue
+ }
+
+ if !x.IsInt64() {
+ t.Errorf("IsInt64(%s) failed unexpectedly", s)
+ }
+
+ got := x.Int64()
+ if got != want {
+ t.Errorf("Int64(%s) = %d; want %d", s, got, want)
}
}
}
-var uint64Tests = []uint64{
- 0,
- 1,
- 4294967295,
- 4294967296,
- 8589934591,
- 8589934592,
- 9223372036854775807,
- 9223372036854775808,
- 18446744073709551615, // 1<<64 - 1
+var uint64Tests = []string{
+ // uint64
+ "0",
+ "1",
+ "4294967295",
+ "4294967296",
+ "8589934591",
+ "8589934592",
+ "9223372036854775807",
+ "9223372036854775808",
+ "0x08000000000000000",
+
+ // not uint64
+ "0x10000000000000000",
+ "-0x08000000000000000",
+ "-1",
}
func TestUint64(t *testing.T) {
- in := new(Int)
- for i, testVal := range uint64Tests {
- in.SetUint64(testVal)
- out := in.Uint64()
-
- if out != testVal {
- t.Errorf("#%d got %d want %d", i, out, testVal)
+ for _, s := range uint64Tests {
+ var x Int
+ _, ok := x.SetString(s, 0)
+ if !ok {
+ t.Errorf("SetString(%s, 0) failed", s)
+ continue
}
- str := fmt.Sprint(testVal)
- strOut := in.String()
- if strOut != str {
- t.Errorf("#%d.String got %s want %s", i, strOut, str)
+ want, err := strconv.ParseUint(s, 0, 64)
+ if err != nil {
+ // check for sign explicitly (ErrRange doesn't cover signed input)
+ if s[0] == '-' || err.(*strconv.NumError).Err == strconv.ErrRange {
+ if x.IsUint64() {
+ t.Errorf("IsUint64(%s) succeeded unexpectedly", s)
+ }
+ } else {
+ t.Errorf("ParseUint(%s) failed", s)
+ }
+ continue
+ }
+
+ if !x.IsUint64() {
+ t.Errorf("IsUint64(%s) failed unexpectedly", s)
+ }
+
+ got := x.Uint64()
+ if got != want {
+ t.Errorf("Uint64(%s) = %d; want %d", s, got, want)
}
}
}