]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: add IsInt64/IsUint64 predicates
authorRobert Griesemer <gri@golang.org>
Tue, 7 Feb 2017 19:34:20 +0000 (11:34 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 7 Feb 2017 23:02:33 +0000 (23:02 +0000)
Change-Id: Ia5ed3919cb492009ac8f66d175b47a69f83ee4f1
Reviewed-on: https://go-review.googlesource.com/36487
Reviewed-by: Alan Donovan <adonovan@google.com>
src/math/big/int.go
src/math/big/int_test.go

index 1d8dabce12b65ad0bdaa03b2aac66c2d6dfe972b..bed8d60a5ed3b45ae4015e45fb91f6a9be0aa638 100644 (file)
@@ -324,22 +324,22 @@ func (x *Int) Cmp(y *Int) (r int) {
        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 @@ func (x *Int) Uint64() uint64 {
        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,
index b8e0778ca3201783a524a5c473754d74f94db946..155ccee6af175baaf8c6738e908eb4a6247b5de5 100644 (file)
@@ -7,8 +7,8 @@ package big
 import (
        "bytes"
        "encoding/hex"
-       "fmt"
        "math/rand"
+       "strconv"
        "strings"
        "testing"
        "testing/quick"
@@ -903,56 +903,105 @@ func TestLshRsh(t *testing.T) {
        }
 }
 
-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
+               }
+
+               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 {
-                       t.Errorf("#%d got %d want %d", i, out, testVal)
+               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()
+       for _, s := range uint64Tests {
+               var x Int
+               _, ok := x.SetString(s, 0)
+               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 {
-                       t.Errorf("#%d got %d want %d", i, out, testVal)
+               if !x.IsUint64() {
+                       t.Errorf("IsUint64(%s) failed unexpectedly", s)
                }
 
-               str := fmt.Sprint(testVal)
-               strOut := in.String()
-               if strOut != str {
-                       t.Errorf("#%d.String got %s want %s", i, strOut, str)
+               got := x.Uint64()
+               if got != want {
+                       t.Errorf("Uint64(%s) = %d; want %d", s, got, want)
                }
        }
 }