Commit 1f93ba66 authored by Robert Griesemer's avatar Robert Griesemer

math/big: add IsInt64/IsUint64 predicates

Change-Id: Ia5ed3919cb492009ac8f66d175b47a69f83ee4f1
Reviewed-on: https://go-review.googlesource.com/36487Reviewed-by: 's avatarAlan Donovan <adonovan@google.com>
parent 7bad0036
...@@ -324,22 +324,22 @@ func (x *Int) Cmp(y *Int) (r int) { ...@@ -324,22 +324,22 @@ func (x *Int) Cmp(y *Int) (r int) {
return return
} }
// low32 returns the least significant 32 bits of z. // low32 returns the least significant 32 bits of x.
func low32(z nat) uint32 { func low32(x nat) uint32 {
if len(z) == 0 { if len(x) == 0 {
return 0 return 0
} }
return uint32(z[0]) return uint32(x[0])
} }
// low64 returns the least significant 64 bits of z. // low64 returns the least significant 64 bits of x.
func low64(z nat) uint64 { func low64(x nat) uint64 {
if len(z) == 0 { if len(x) == 0 {
return 0 return 0
} }
v := uint64(z[0]) v := uint64(x[0])
if _W == 32 && len(z) > 1 { if _W == 32 && len(x) > 1 {
v |= uint64(z[1]) << 32 return uint64(x[1])<<32 | v
} }
return v return v
} }
...@@ -360,6 +360,20 @@ func (x *Int) Uint64() uint64 { ...@@ -360,6 +360,20 @@ func (x *Int) Uint64() uint64 {
return low64(x.abs) 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, // SetString sets z to the value of s, interpreted in the given base,
// and returns z and a boolean indicating success. The entire string // and returns z and a boolean indicating success. The entire string
// (not just a prefix) must be valid for success. If SetString fails, // (not just a prefix) must be valid for success. If SetString fails,
......
...@@ -7,8 +7,8 @@ package big ...@@ -7,8 +7,8 @@ package big
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"fmt"
"math/rand" "math/rand"
"strconv"
"strings" "strings"
"testing" "testing"
"testing/quick" "testing/quick"
...@@ -903,56 +903,105 @@ func TestLshRsh(t *testing.T) { ...@@ -903,56 +903,105 @@ func TestLshRsh(t *testing.T) {
} }
} }
var int64Tests = []int64{ var int64Tests = []string{
0, // int64
1, "0",
-1, "1",
4294967295, "-1",
-4294967295, "4294967295",
4294967296, "-4294967295",
-4294967296, "4294967296",
9223372036854775807, "-4294967296",
-9223372036854775807, "9223372036854775807",
-9223372036854775808, "-9223372036854775807",
"-9223372036854775808",
// not int64
"0x8000000000000000",
"-0x8000000000000001",
"38579843757496759476987459679745",
"-38579843757496759476987459679745",
} }
func TestInt64(t *testing.T) { func TestInt64(t *testing.T) {
for i, testVal := range int64Tests { for _, s := range int64Tests {
in := NewInt(testVal) var x Int
out := in.Int64() _, ok := x.SetString(s, 0)
if !ok {
t.Errorf("SetString(%s, 0) failed", s)
continue
}
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)
}
if out != testVal { got := x.Int64()
t.Errorf("#%d got %d want %d", i, out, testVal) if got != want {
t.Errorf("Int64(%s) = %d; want %d", s, got, want)
} }
} }
} }
var uint64Tests = []uint64{ var uint64Tests = []string{
0, // uint64
1, "0",
4294967295, "1",
4294967296, "4294967295",
8589934591, "4294967296",
8589934592, "8589934591",
9223372036854775807, "8589934592",
9223372036854775808, "9223372036854775807",
18446744073709551615, // 1<<64 - 1 "9223372036854775808",
"0x08000000000000000",
// not uint64
"0x10000000000000000",
"-0x08000000000000000",
"-1",
} }
func TestUint64(t *testing.T) { func TestUint64(t *testing.T) {
in := new(Int) for _, s := range uint64Tests {
for i, testVal := range uint64Tests { var x Int
in.SetUint64(testVal) _, ok := x.SetString(s, 0)
out := in.Uint64() if !ok {
t.Errorf("SetString(%s, 0) failed", s)
continue
}
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 out != testVal { if !x.IsUint64() {
t.Errorf("#%d got %d want %d", i, out, testVal) t.Errorf("IsUint64(%s) failed unexpectedly", s)
} }
str := fmt.Sprint(testVal) got := x.Uint64()
strOut := in.String() if got != want {
if strOut != str { t.Errorf("Uint64(%s) = %d; want %d", s, got, want)
t.Errorf("#%d.String got %s want %s", i, strOut, str)
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment