]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: split int conversion routines and tests into separate files
authorRobert Griesemer <gri@golang.org>
Fri, 30 Jan 2015 22:25:55 +0000 (14:25 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 30 Jan 2015 23:02:35 +0000 (23:02 +0000)
No other functional changes.

Change-Id: If0d9e6208d53478e70d991b6926ea196b2cccf2e
Reviewed-on: https://go-review.googlesource.com/3672
Reviewed-by: Alan Donovan <adonovan@google.com>
src/math/big/int.go
src/math/big/int_test.go
src/math/big/intconv.go [new file with mode: 0644]
src/math/big/intconv_test.go [new file with mode: 0644]

index 3a4d2273354f7427d68f070b2ec7a71a6cacebc5..5c1b2cd7653fa55a21eddbd7bc68d4cdd965919a 100644 (file)
@@ -321,221 +321,6 @@ func (x *Int) Cmp(y *Int) (r int) {
        return
 }
 
-func (x *Int) String() string {
-       switch {
-       case x == nil:
-               return "<nil>"
-       case x.neg:
-               return "-" + x.abs.decimalString()
-       }
-       return x.abs.decimalString()
-}
-
-func charset(ch rune) string {
-       switch ch {
-       case 'b':
-               return lowercaseDigits[0:2]
-       case 'o':
-               return lowercaseDigits[0:8]
-       case 'd', 's', 'v':
-               return lowercaseDigits[0:10]
-       case 'x':
-               return lowercaseDigits[0:16]
-       case 'X':
-               return uppercaseDigits[0:16]
-       }
-       return "" // unknown format
-}
-
-// write count copies of text to s
-func writeMultiple(s fmt.State, text string, count int) {
-       if len(text) > 0 {
-               b := []byte(text)
-               for ; count > 0; count-- {
-                       s.Write(b)
-               }
-       }
-}
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
-// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
-// Also supported are the full suite of package fmt's format
-// verbs for integral types, including '+', '-', and ' '
-// for sign control, '#' for leading zero in octal and for
-// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
-// respectively, specification of minimum digits precision,
-// output field width, space or zero padding, and left or
-// right justification.
-//
-func (x *Int) Format(s fmt.State, ch rune) {
-       cs := charset(ch)
-
-       // special cases
-       switch {
-       case cs == "":
-               // unknown format
-               fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
-               return
-       case x == nil:
-               fmt.Fprint(s, "<nil>")
-               return
-       }
-
-       // determine sign character
-       sign := ""
-       switch {
-       case x.neg:
-               sign = "-"
-       case s.Flag('+'): // supersedes ' ' when both specified
-               sign = "+"
-       case s.Flag(' '):
-               sign = " "
-       }
-
-       // determine prefix characters for indicating output base
-       prefix := ""
-       if s.Flag('#') {
-               switch ch {
-               case 'o': // octal
-                       prefix = "0"
-               case 'x': // hexadecimal
-                       prefix = "0x"
-               case 'X':
-                       prefix = "0X"
-               }
-       }
-
-       // determine digits with base set by len(cs) and digit characters from cs
-       digits := x.abs.string(cs)
-
-       // number of characters for the three classes of number padding
-       var left int   // space characters to left of digits for right justification ("%8d")
-       var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
-       var right int  // space characters to right of digits for left justification ("%-8d")
-
-       // determine number padding from precision: the least number of digits to output
-       precision, precisionSet := s.Precision()
-       if precisionSet {
-               switch {
-               case len(digits) < precision:
-                       zeroes = precision - len(digits) // count of zero padding
-               case digits == "0" && precision == 0:
-                       return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
-               }
-       }
-
-       // determine field pad from width: the least number of characters to output
-       length := len(sign) + len(prefix) + zeroes + len(digits)
-       if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
-               switch d := width - length; {
-               case s.Flag('-'):
-                       // pad on the right with spaces; supersedes '0' when both specified
-                       right = d
-               case s.Flag('0') && !precisionSet:
-                       // pad with zeroes unless precision also specified
-                       zeroes = d
-               default:
-                       // pad on the left with spaces
-                       left = d
-               }
-       }
-
-       // print number as [left pad][sign][prefix][zero pad][digits][right pad]
-       writeMultiple(s, " ", left)
-       writeMultiple(s, sign, 1)
-       writeMultiple(s, prefix, 1)
-       writeMultiple(s, "0", zeroes)
-       writeMultiple(s, digits, 1)
-       writeMultiple(s, " ", right)
-}
-
-// scan sets z to the integer value corresponding to the longest possible prefix
-// read from r representing a signed integer number in a given conversion base.
-// It returns z, the actual conversion base used, and an error, if any. In the
-// error case, the value of z is undefined but the returned value is nil. The
-// syntax follows the syntax of integer literals in Go.
-//
-// The base argument must be 0 or a value from 2 through MaxBase. If the base
-// is 0, the string prefix determines the actual conversion base. A prefix of
-// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
-// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
-//
-func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
-       // determine sign
-       neg, err := scanSign(r)
-       if err != nil {
-               return nil, 0, err
-       }
-
-       // determine mantissa
-       z.abs, base, _, err = z.abs.scan(r, base, false)
-       if err != nil {
-               return nil, base, err
-       }
-       z.neg = len(z.abs) > 0 && neg // 0 has no sign
-
-       return z, base, nil
-}
-
-func scanSign(r io.ByteScanner) (neg bool, err error) {
-       var ch byte
-       if ch, err = r.ReadByte(); err != nil {
-               return false, err
-       }
-       switch ch {
-       case '-':
-               neg = true
-       case '+':
-               // nothing to do
-       default:
-               r.UnreadByte()
-       }
-       return
-}
-
-// byteReader is a local wrapper around fmt.ScanState;
-// it implements the ByteReader interface.
-type byteReader struct {
-       fmt.ScanState
-}
-
-func (r byteReader) ReadByte() (byte, error) {
-       ch, size, err := r.ReadRune()
-       if size != 1 && err == nil {
-               err = fmt.Errorf("invalid rune %#U", ch)
-       }
-       return byte(ch), err
-}
-
-func (r byteReader) UnreadByte() error {
-       return r.UnreadRune()
-}
-
-// Scan is a support routine for fmt.Scanner; it sets z to the value of
-// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
-// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
-func (z *Int) Scan(s fmt.ScanState, ch rune) error {
-       s.SkipSpace() // skip leading space characters
-       base := 0
-       switch ch {
-       case 'b':
-               base = 2
-       case 'o':
-               base = 8
-       case 'd':
-               base = 10
-       case 'x', 'X':
-               base = 16
-       case 's', 'v':
-               // let scan determine the base
-       default:
-               return errors.New("Int.Scan: invalid verb")
-       }
-       _, _, err := z.scan(byteReader{s}, base)
-       return err
-}
-
 // low32 returns the least significant 32 bits of z.
 func low32(z nat) uint32 {
        if len(z) == 0 {
index d373e842c6786cbe1c15d6e70f70a306fde61748..1418dca3352adeaa49ed032e822f29770049eda4 100644 (file)
@@ -219,337 +219,6 @@ func TestMulRangeZ(t *testing.T) {
        }
 }
 
-var stringTests = []struct {
-       in   string
-       out  string
-       base int
-       val  int64
-       ok   bool
-}{
-       {in: "", ok: false},
-       {in: "a", ok: false},
-       {in: "z", ok: false},
-       {in: "+", ok: false},
-       {in: "-", ok: false},
-       {in: "0b", ok: false},
-       {in: "0x", ok: false},
-       {in: "2", base: 2, ok: false},
-       {in: "0b2", base: 0, ok: false},
-       {in: "08", ok: false},
-       {in: "8", base: 8, ok: false},
-       {in: "0xg", base: 0, ok: false},
-       {in: "g", base: 16, ok: false},
-       {"0", "0", 0, 0, true},
-       {"0", "0", 10, 0, true},
-       {"0", "0", 16, 0, true},
-       {"+0", "0", 0, 0, true},
-       {"-0", "0", 0, 0, true},
-       {"10", "10", 0, 10, true},
-       {"10", "10", 10, 10, true},
-       {"10", "10", 16, 16, true},
-       {"-10", "-10", 16, -16, true},
-       {"+10", "10", 16, 16, true},
-       {"0x10", "16", 0, 16, true},
-       {in: "0x10", base: 16, ok: false},
-       {"-0x10", "-16", 0, -16, true},
-       {"+0x10", "16", 0, 16, true},
-       {"00", "0", 0, 0, true},
-       {"0", "0", 8, 0, true},
-       {"07", "7", 0, 7, true},
-       {"7", "7", 8, 7, true},
-       {"023", "19", 0, 19, true},
-       {"23", "23", 8, 19, true},
-       {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
-       {"0b0", "0", 0, 0, true},
-       {"-111", "-111", 2, -7, true},
-       {"-0b111", "-7", 0, -7, true},
-       {"0b1001010111", "599", 0, 0x257, true},
-       {"1001010111", "1001010111", 2, 0x257, true},
-}
-
-func format(base int) string {
-       switch base {
-       case 2:
-               return "%b"
-       case 8:
-               return "%o"
-       case 16:
-               return "%x"
-       }
-       return "%d"
-}
-
-func TestGetString(t *testing.T) {
-       z := new(Int)
-       for i, test := range stringTests {
-               if !test.ok {
-                       continue
-               }
-               z.SetInt64(test.val)
-
-               if test.base == 10 {
-                       s := z.String()
-                       if s != test.out {
-                               t.Errorf("#%da got %s; want %s", i, s, test.out)
-                       }
-               }
-
-               s := fmt.Sprintf(format(test.base), z)
-               if s != test.out {
-                       t.Errorf("#%db got %s; want %s", i, s, test.out)
-               }
-       }
-}
-
-func TestSetString(t *testing.T) {
-       tmp := new(Int)
-       for i, test := range stringTests {
-               // initialize to a non-zero value so that issues with parsing
-               // 0 are detected
-               tmp.SetInt64(1234567890)
-               n1, ok1 := new(Int).SetString(test.in, test.base)
-               n2, ok2 := tmp.SetString(test.in, test.base)
-               expected := NewInt(test.val)
-               if ok1 != test.ok || ok2 != test.ok {
-                       t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
-                       continue
-               }
-               if !ok1 {
-                       if n1 != nil {
-                               t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
-                       }
-                       continue
-               }
-               if !ok2 {
-                       if n2 != nil {
-                               t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
-                       }
-                       continue
-               }
-
-               if ok1 && !isNormalized(n1) {
-                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
-               }
-               if ok2 && !isNormalized(n2) {
-                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
-               }
-
-               if n1.Cmp(expected) != 0 {
-                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
-               }
-               if n2.Cmp(expected) != 0 {
-                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
-               }
-       }
-}
-
-var formatTests = []struct {
-       input  string
-       format string
-       output string
-}{
-       {"<nil>", "%x", "<nil>"},
-       {"<nil>", "%#x", "<nil>"},
-       {"<nil>", "%#y", "%!y(big.Int=<nil>)"},
-
-       {"10", "%b", "1010"},
-       {"10", "%o", "12"},
-       {"10", "%d", "10"},
-       {"10", "%v", "10"},
-       {"10", "%x", "a"},
-       {"10", "%X", "A"},
-       {"-10", "%X", "-A"},
-       {"10", "%y", "%!y(big.Int=10)"},
-       {"-10", "%y", "%!y(big.Int=-10)"},
-
-       {"10", "%#b", "1010"},
-       {"10", "%#o", "012"},
-       {"10", "%#d", "10"},
-       {"10", "%#v", "10"},
-       {"10", "%#x", "0xa"},
-       {"10", "%#X", "0XA"},
-       {"-10", "%#X", "-0XA"},
-       {"10", "%#y", "%!y(big.Int=10)"},
-       {"-10", "%#y", "%!y(big.Int=-10)"},
-
-       {"1234", "%d", "1234"},
-       {"1234", "%3d", "1234"},
-       {"1234", "%4d", "1234"},
-       {"-1234", "%d", "-1234"},
-       {"1234", "% 5d", " 1234"},
-       {"1234", "%+5d", "+1234"},
-       {"1234", "%-5d", "1234 "},
-       {"1234", "%x", "4d2"},
-       {"1234", "%X", "4D2"},
-       {"-1234", "%3x", "-4d2"},
-       {"-1234", "%4x", "-4d2"},
-       {"-1234", "%5x", " -4d2"},
-       {"-1234", "%-5x", "-4d2 "},
-       {"1234", "%03d", "1234"},
-       {"1234", "%04d", "1234"},
-       {"1234", "%05d", "01234"},
-       {"1234", "%06d", "001234"},
-       {"-1234", "%06d", "-01234"},
-       {"1234", "%+06d", "+01234"},
-       {"1234", "% 06d", " 01234"},
-       {"1234", "%-6d", "1234  "},
-       {"1234", "%-06d", "1234  "},
-       {"-1234", "%-06d", "-1234 "},
-
-       {"1234", "%.3d", "1234"},
-       {"1234", "%.4d", "1234"},
-       {"1234", "%.5d", "01234"},
-       {"1234", "%.6d", "001234"},
-       {"-1234", "%.3d", "-1234"},
-       {"-1234", "%.4d", "-1234"},
-       {"-1234", "%.5d", "-01234"},
-       {"-1234", "%.6d", "-001234"},
-
-       {"1234", "%8.3d", "    1234"},
-       {"1234", "%8.4d", "    1234"},
-       {"1234", "%8.5d", "   01234"},
-       {"1234", "%8.6d", "  001234"},
-       {"-1234", "%8.3d", "   -1234"},
-       {"-1234", "%8.4d", "   -1234"},
-       {"-1234", "%8.5d", "  -01234"},
-       {"-1234", "%8.6d", " -001234"},
-
-       {"1234", "%+8.3d", "   +1234"},
-       {"1234", "%+8.4d", "   +1234"},
-       {"1234", "%+8.5d", "  +01234"},
-       {"1234", "%+8.6d", " +001234"},
-       {"-1234", "%+8.3d", "   -1234"},
-       {"-1234", "%+8.4d", "   -1234"},
-       {"-1234", "%+8.5d", "  -01234"},
-       {"-1234", "%+8.6d", " -001234"},
-
-       {"1234", "% 8.3d", "    1234"},
-       {"1234", "% 8.4d", "    1234"},
-       {"1234", "% 8.5d", "   01234"},
-       {"1234", "% 8.6d", "  001234"},
-       {"-1234", "% 8.3d", "   -1234"},
-       {"-1234", "% 8.4d", "   -1234"},
-       {"-1234", "% 8.5d", "  -01234"},
-       {"-1234", "% 8.6d", " -001234"},
-
-       {"1234", "%.3x", "4d2"},
-       {"1234", "%.4x", "04d2"},
-       {"1234", "%.5x", "004d2"},
-       {"1234", "%.6x", "0004d2"},
-       {"-1234", "%.3x", "-4d2"},
-       {"-1234", "%.4x", "-04d2"},
-       {"-1234", "%.5x", "-004d2"},
-       {"-1234", "%.6x", "-0004d2"},
-
-       {"1234", "%8.3x", "     4d2"},
-       {"1234", "%8.4x", "    04d2"},
-       {"1234", "%8.5x", "   004d2"},
-       {"1234", "%8.6x", "  0004d2"},
-       {"-1234", "%8.3x", "    -4d2"},
-       {"-1234", "%8.4x", "   -04d2"},
-       {"-1234", "%8.5x", "  -004d2"},
-       {"-1234", "%8.6x", " -0004d2"},
-
-       {"1234", "%+8.3x", "    +4d2"},
-       {"1234", "%+8.4x", "   +04d2"},
-       {"1234", "%+8.5x", "  +004d2"},
-       {"1234", "%+8.6x", " +0004d2"},
-       {"-1234", "%+8.3x", "    -4d2"},
-       {"-1234", "%+8.4x", "   -04d2"},
-       {"-1234", "%+8.5x", "  -004d2"},
-       {"-1234", "%+8.6x", " -0004d2"},
-
-       {"1234", "% 8.3x", "     4d2"},
-       {"1234", "% 8.4x", "    04d2"},
-       {"1234", "% 8.5x", "   004d2"},
-       {"1234", "% 8.6x", "  0004d2"},
-       {"1234", "% 8.7x", " 00004d2"},
-       {"1234", "% 8.8x", " 000004d2"},
-       {"-1234", "% 8.3x", "    -4d2"},
-       {"-1234", "% 8.4x", "   -04d2"},
-       {"-1234", "% 8.5x", "  -004d2"},
-       {"-1234", "% 8.6x", " -0004d2"},
-       {"-1234", "% 8.7x", "-00004d2"},
-       {"-1234", "% 8.8x", "-000004d2"},
-
-       {"1234", "%-8.3d", "1234    "},
-       {"1234", "%-8.4d", "1234    "},
-       {"1234", "%-8.5d", "01234   "},
-       {"1234", "%-8.6d", "001234  "},
-       {"1234", "%-8.7d", "0001234 "},
-       {"1234", "%-8.8d", "00001234"},
-       {"-1234", "%-8.3d", "-1234   "},
-       {"-1234", "%-8.4d", "-1234   "},
-       {"-1234", "%-8.5d", "-01234  "},
-       {"-1234", "%-8.6d", "-001234 "},
-       {"-1234", "%-8.7d", "-0001234"},
-       {"-1234", "%-8.8d", "-00001234"},
-
-       {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
-
-       {"0", "%.d", ""},
-       {"0", "%.0d", ""},
-       {"0", "%3.d", ""},
-}
-
-func TestFormat(t *testing.T) {
-       for i, test := range formatTests {
-               var x *Int
-               if test.input != "<nil>" {
-                       var ok bool
-                       x, ok = new(Int).SetString(test.input, 0)
-                       if !ok {
-                               t.Errorf("#%d failed reading input %s", i, test.input)
-                       }
-               }
-               output := fmt.Sprintf(test.format, x)
-               if output != test.output {
-                       t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
-               }
-       }
-}
-
-var scanTests = []struct {
-       input     string
-       format    string
-       output    string
-       remaining int
-}{
-       {"1010", "%b", "10", 0},
-       {"0b1010", "%v", "10", 0},
-       {"12", "%o", "10", 0},
-       {"012", "%v", "10", 0},
-       {"10", "%d", "10", 0},
-       {"10", "%v", "10", 0},
-       {"a", "%x", "10", 0},
-       {"0xa", "%v", "10", 0},
-       {"A", "%X", "10", 0},
-       {"-A", "%X", "-10", 0},
-       {"+0b1011001", "%v", "89", 0},
-       {"0xA", "%v", "10", 0},
-       {"0 ", "%v", "0", 1},
-       {"2+3", "%v", "2", 2},
-       {"0XABC 12", "%v", "2748", 3},
-}
-
-func TestScan(t *testing.T) {
-       var buf bytes.Buffer
-       for i, test := range scanTests {
-               x := new(Int)
-               buf.Reset()
-               buf.WriteString(test.input)
-               if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
-                       t.Errorf("#%d error: %s", i, err)
-               }
-               if x.String() != test.output {
-                       t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
-               }
-               if buf.Len() != test.remaining {
-                       t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
-               }
-       }
-}
-
 // Examples from the Go Language Spec, section "Arithmetic operators"
 var divisionSignsTests = []struct {
        x, y int64
diff --git a/src/math/big/intconv.go b/src/math/big/intconv.go
new file mode 100644 (file)
index 0000000..9c68a22
--- /dev/null
@@ -0,0 +1,228 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements int-to-string conversion functions.
+
+package big
+
+import (
+       "errors"
+       "fmt"
+       "io"
+)
+
+func (x *Int) String() string {
+       switch {
+       case x == nil:
+               return "<nil>"
+       case x.neg:
+               return "-" + x.abs.decimalString()
+       }
+       return x.abs.decimalString()
+}
+
+func charset(ch rune) string {
+       switch ch {
+       case 'b':
+               return lowercaseDigits[0:2]
+       case 'o':
+               return lowercaseDigits[0:8]
+       case 'd', 's', 'v':
+               return lowercaseDigits[0:10]
+       case 'x':
+               return lowercaseDigits[0:16]
+       case 'X':
+               return uppercaseDigits[0:16]
+       }
+       return "" // unknown format
+}
+
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+       if len(text) > 0 {
+               b := []byte(text)
+               for ; count > 0; count-- {
+                       s.Write(b)
+               }
+       }
+}
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
+//
+func (x *Int) Format(s fmt.State, ch rune) {
+       cs := charset(ch)
+
+       // special cases
+       switch {
+       case cs == "":
+               // unknown format
+               fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+               return
+       case x == nil:
+               fmt.Fprint(s, "<nil>")
+               return
+       }
+
+       // determine sign character
+       sign := ""
+       switch {
+       case x.neg:
+               sign = "-"
+       case s.Flag('+'): // supersedes ' ' when both specified
+               sign = "+"
+       case s.Flag(' '):
+               sign = " "
+       }
+
+       // determine prefix characters for indicating output base
+       prefix := ""
+       if s.Flag('#') {
+               switch ch {
+               case 'o': // octal
+                       prefix = "0"
+               case 'x': // hexadecimal
+                       prefix = "0x"
+               case 'X':
+                       prefix = "0X"
+               }
+       }
+
+       // determine digits with base set by len(cs) and digit characters from cs
+       digits := x.abs.string(cs)
+
+       // number of characters for the three classes of number padding
+       var left int   // space characters to left of digits for right justification ("%8d")
+       var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+       var right int  // space characters to right of digits for left justification ("%-8d")
+
+       // determine number padding from precision: the least number of digits to output
+       precision, precisionSet := s.Precision()
+       if precisionSet {
+               switch {
+               case len(digits) < precision:
+                       zeroes = precision - len(digits) // count of zero padding
+               case digits == "0" && precision == 0:
+                       return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+               }
+       }
+
+       // determine field pad from width: the least number of characters to output
+       length := len(sign) + len(prefix) + zeroes + len(digits)
+       if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+               switch d := width - length; {
+               case s.Flag('-'):
+                       // pad on the right with spaces; supersedes '0' when both specified
+                       right = d
+               case s.Flag('0') && !precisionSet:
+                       // pad with zeroes unless precision also specified
+                       zeroes = d
+               default:
+                       // pad on the left with spaces
+                       left = d
+               }
+       }
+
+       // print number as [left pad][sign][prefix][zero pad][digits][right pad]
+       writeMultiple(s, " ", left)
+       writeMultiple(s, sign, 1)
+       writeMultiple(s, prefix, 1)
+       writeMultiple(s, "0", zeroes)
+       writeMultiple(s, digits, 1)
+       writeMultiple(s, " ", right)
+}
+
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined but the returned value is nil. The
+// syntax follows the syntax of integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
+       // determine sign
+       neg, err := scanSign(r)
+       if err != nil {
+               return nil, 0, err
+       }
+
+       // determine mantissa
+       z.abs, base, _, err = z.abs.scan(r, base, false)
+       if err != nil {
+               return nil, base, err
+       }
+       z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+       return z, base, nil
+}
+
+func scanSign(r io.ByteScanner) (neg bool, err error) {
+       var ch byte
+       if ch, err = r.ReadByte(); err != nil {
+               return false, err
+       }
+       switch ch {
+       case '-':
+               neg = true
+       case '+':
+               // nothing to do
+       default:
+               r.UnreadByte()
+       }
+       return
+}
+
+// byteReader is a local wrapper around fmt.ScanState;
+// it implements the ByteReader interface.
+type byteReader struct {
+       fmt.ScanState
+}
+
+func (r byteReader) ReadByte() (byte, error) {
+       ch, size, err := r.ReadRune()
+       if size != 1 && err == nil {
+               err = fmt.Errorf("invalid rune %#U", ch)
+       }
+       return byte(ch), err
+}
+
+func (r byteReader) UnreadByte() error {
+       return r.UnreadRune()
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch rune) error {
+       s.SkipSpace() // skip leading space characters
+       base := 0
+       switch ch {
+       case 'b':
+               base = 2
+       case 'o':
+               base = 8
+       case 'd':
+               base = 10
+       case 'x', 'X':
+               base = 16
+       case 's', 'v':
+               // let scan determine the base
+       default:
+               return errors.New("Int.Scan: invalid verb")
+       }
+       _, _, err := z.scan(byteReader{s}, base)
+       return err
+}
diff --git a/src/math/big/intconv_test.go b/src/math/big/intconv_test.go
new file mode 100644 (file)
index 0000000..2deb84b
--- /dev/null
@@ -0,0 +1,342 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+       "bytes"
+       "fmt"
+       "testing"
+)
+
+var stringTests = []struct {
+       in   string
+       out  string
+       base int
+       val  int64
+       ok   bool
+}{
+       {in: "", ok: false},
+       {in: "a", ok: false},
+       {in: "z", ok: false},
+       {in: "+", ok: false},
+       {in: "-", ok: false},
+       {in: "0b", ok: false},
+       {in: "0x", ok: false},
+       {in: "2", base: 2, ok: false},
+       {in: "0b2", base: 0, ok: false},
+       {in: "08", ok: false},
+       {in: "8", base: 8, ok: false},
+       {in: "0xg", base: 0, ok: false},
+       {in: "g", base: 16, ok: false},
+       {"0", "0", 0, 0, true},
+       {"0", "0", 10, 0, true},
+       {"0", "0", 16, 0, true},
+       {"+0", "0", 0, 0, true},
+       {"-0", "0", 0, 0, true},
+       {"10", "10", 0, 10, true},
+       {"10", "10", 10, 10, true},
+       {"10", "10", 16, 16, true},
+       {"-10", "-10", 16, -16, true},
+       {"+10", "10", 16, 16, true},
+       {"0x10", "16", 0, 16, true},
+       {in: "0x10", base: 16, ok: false},
+       {"-0x10", "-16", 0, -16, true},
+       {"+0x10", "16", 0, 16, true},
+       {"00", "0", 0, 0, true},
+       {"0", "0", 8, 0, true},
+       {"07", "7", 0, 7, true},
+       {"7", "7", 8, 7, true},
+       {"023", "19", 0, 19, true},
+       {"23", "23", 8, 19, true},
+       {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+       {"0b0", "0", 0, 0, true},
+       {"-111", "-111", 2, -7, true},
+       {"-0b111", "-7", 0, -7, true},
+       {"0b1001010111", "599", 0, 0x257, true},
+       {"1001010111", "1001010111", 2, 0x257, true},
+}
+
+func format(base int) string {
+       switch base {
+       case 2:
+               return "%b"
+       case 8:
+               return "%o"
+       case 16:
+               return "%x"
+       }
+       return "%d"
+}
+
+func TestGetString(t *testing.T) {
+       z := new(Int)
+       for i, test := range stringTests {
+               if !test.ok {
+                       continue
+               }
+               z.SetInt64(test.val)
+
+               if test.base == 10 {
+                       s := z.String()
+                       if s != test.out {
+                               t.Errorf("#%da got %s; want %s", i, s, test.out)
+                       }
+               }
+
+               s := fmt.Sprintf(format(test.base), z)
+               if s != test.out {
+                       t.Errorf("#%db got %s; want %s", i, s, test.out)
+               }
+       }
+}
+
+func TestSetString(t *testing.T) {
+       tmp := new(Int)
+       for i, test := range stringTests {
+               // initialize to a non-zero value so that issues with parsing
+               // 0 are detected
+               tmp.SetInt64(1234567890)
+               n1, ok1 := new(Int).SetString(test.in, test.base)
+               n2, ok2 := tmp.SetString(test.in, test.base)
+               expected := NewInt(test.val)
+               if ok1 != test.ok || ok2 != test.ok {
+                       t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+                       continue
+               }
+               if !ok1 {
+                       if n1 != nil {
+                               t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
+                       }
+                       continue
+               }
+               if !ok2 {
+                       if n2 != nil {
+                               t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
+                       }
+                       continue
+               }
+
+               if ok1 && !isNormalized(n1) {
+                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+               }
+               if ok2 && !isNormalized(n2) {
+                       t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+               }
+
+               if n1.Cmp(expected) != 0 {
+                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+               }
+               if n2.Cmp(expected) != 0 {
+                       t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+               }
+       }
+}
+
+var formatTests = []struct {
+       input  string
+       format string
+       output string
+}{
+       {"<nil>", "%x", "<nil>"},
+       {"<nil>", "%#x", "<nil>"},
+       {"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+       {"10", "%b", "1010"},
+       {"10", "%o", "12"},
+       {"10", "%d", "10"},
+       {"10", "%v", "10"},
+       {"10", "%x", "a"},
+       {"10", "%X", "A"},
+       {"-10", "%X", "-A"},
+       {"10", "%y", "%!y(big.Int=10)"},
+       {"-10", "%y", "%!y(big.Int=-10)"},
+
+       {"10", "%#b", "1010"},
+       {"10", "%#o", "012"},
+       {"10", "%#d", "10"},
+       {"10", "%#v", "10"},
+       {"10", "%#x", "0xa"},
+       {"10", "%#X", "0XA"},
+       {"-10", "%#X", "-0XA"},
+       {"10", "%#y", "%!y(big.Int=10)"},
+       {"-10", "%#y", "%!y(big.Int=-10)"},
+
+       {"1234", "%d", "1234"},
+       {"1234", "%3d", "1234"},
+       {"1234", "%4d", "1234"},
+       {"-1234", "%d", "-1234"},
+       {"1234", "% 5d", " 1234"},
+       {"1234", "%+5d", "+1234"},
+       {"1234", "%-5d", "1234 "},
+       {"1234", "%x", "4d2"},
+       {"1234", "%X", "4D2"},
+       {"-1234", "%3x", "-4d2"},
+       {"-1234", "%4x", "-4d2"},
+       {"-1234", "%5x", " -4d2"},
+       {"-1234", "%-5x", "-4d2 "},
+       {"1234", "%03d", "1234"},
+       {"1234", "%04d", "1234"},
+       {"1234", "%05d", "01234"},
+       {"1234", "%06d", "001234"},
+       {"-1234", "%06d", "-01234"},
+       {"1234", "%+06d", "+01234"},
+       {"1234", "% 06d", " 01234"},
+       {"1234", "%-6d", "1234  "},
+       {"1234", "%-06d", "1234  "},
+       {"-1234", "%-06d", "-1234 "},
+
+       {"1234", "%.3d", "1234"},
+       {"1234", "%.4d", "1234"},
+       {"1234", "%.5d", "01234"},
+       {"1234", "%.6d", "001234"},
+       {"-1234", "%.3d", "-1234"},
+       {"-1234", "%.4d", "-1234"},
+       {"-1234", "%.5d", "-01234"},
+       {"-1234", "%.6d", "-001234"},
+
+       {"1234", "%8.3d", "    1234"},
+       {"1234", "%8.4d", "    1234"},
+       {"1234", "%8.5d", "   01234"},
+       {"1234", "%8.6d", "  001234"},
+       {"-1234", "%8.3d", "   -1234"},
+       {"-1234", "%8.4d", "   -1234"},
+       {"-1234", "%8.5d", "  -01234"},
+       {"-1234", "%8.6d", " -001234"},
+
+       {"1234", "%+8.3d", "   +1234"},
+       {"1234", "%+8.4d", "   +1234"},
+       {"1234", "%+8.5d", "  +01234"},
+       {"1234", "%+8.6d", " +001234"},
+       {"-1234", "%+8.3d", "   -1234"},
+       {"-1234", "%+8.4d", "   -1234"},
+       {"-1234", "%+8.5d", "  -01234"},
+       {"-1234", "%+8.6d", " -001234"},
+
+       {"1234", "% 8.3d", "    1234"},
+       {"1234", "% 8.4d", "    1234"},
+       {"1234", "% 8.5d", "   01234"},
+       {"1234", "% 8.6d", "  001234"},
+       {"-1234", "% 8.3d", "   -1234"},
+       {"-1234", "% 8.4d", "   -1234"},
+       {"-1234", "% 8.5d", "  -01234"},
+       {"-1234", "% 8.6d", " -001234"},
+
+       {"1234", "%.3x", "4d2"},
+       {"1234", "%.4x", "04d2"},
+       {"1234", "%.5x", "004d2"},
+       {"1234", "%.6x", "0004d2"},
+       {"-1234", "%.3x", "-4d2"},
+       {"-1234", "%.4x", "-04d2"},
+       {"-1234", "%.5x", "-004d2"},
+       {"-1234", "%.6x", "-0004d2"},
+
+       {"1234", "%8.3x", "     4d2"},
+       {"1234", "%8.4x", "    04d2"},
+       {"1234", "%8.5x", "   004d2"},
+       {"1234", "%8.6x", "  0004d2"},
+       {"-1234", "%8.3x", "    -4d2"},
+       {"-1234", "%8.4x", "   -04d2"},
+       {"-1234", "%8.5x", "  -004d2"},
+       {"-1234", "%8.6x", " -0004d2"},
+
+       {"1234", "%+8.3x", "    +4d2"},
+       {"1234", "%+8.4x", "   +04d2"},
+       {"1234", "%+8.5x", "  +004d2"},
+       {"1234", "%+8.6x", " +0004d2"},
+       {"-1234", "%+8.3x", "    -4d2"},
+       {"-1234", "%+8.4x", "   -04d2"},
+       {"-1234", "%+8.5x", "  -004d2"},
+       {"-1234", "%+8.6x", " -0004d2"},
+
+       {"1234", "% 8.3x", "     4d2"},
+       {"1234", "% 8.4x", "    04d2"},
+       {"1234", "% 8.5x", "   004d2"},
+       {"1234", "% 8.6x", "  0004d2"},
+       {"1234", "% 8.7x", " 00004d2"},
+       {"1234", "% 8.8x", " 000004d2"},
+       {"-1234", "% 8.3x", "    -4d2"},
+       {"-1234", "% 8.4x", "   -04d2"},
+       {"-1234", "% 8.5x", "  -004d2"},
+       {"-1234", "% 8.6x", " -0004d2"},
+       {"-1234", "% 8.7x", "-00004d2"},
+       {"-1234", "% 8.8x", "-000004d2"},
+
+       {"1234", "%-8.3d", "1234    "},
+       {"1234", "%-8.4d", "1234    "},
+       {"1234", "%-8.5d", "01234   "},
+       {"1234", "%-8.6d", "001234  "},
+       {"1234", "%-8.7d", "0001234 "},
+       {"1234", "%-8.8d", "00001234"},
+       {"-1234", "%-8.3d", "-1234   "},
+       {"-1234", "%-8.4d", "-1234   "},
+       {"-1234", "%-8.5d", "-01234  "},
+       {"-1234", "%-8.6d", "-001234 "},
+       {"-1234", "%-8.7d", "-0001234"},
+       {"-1234", "%-8.8d", "-00001234"},
+
+       {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+       {"0", "%.d", ""},
+       {"0", "%.0d", ""},
+       {"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+       for i, test := range formatTests {
+               var x *Int
+               if test.input != "<nil>" {
+                       var ok bool
+                       x, ok = new(Int).SetString(test.input, 0)
+                       if !ok {
+                               t.Errorf("#%d failed reading input %s", i, test.input)
+                       }
+               }
+               output := fmt.Sprintf(test.format, x)
+               if output != test.output {
+                       t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+               }
+       }
+}
+
+var scanTests = []struct {
+       input     string
+       format    string
+       output    string
+       remaining int
+}{
+       {"1010", "%b", "10", 0},
+       {"0b1010", "%v", "10", 0},
+       {"12", "%o", "10", 0},
+       {"012", "%v", "10", 0},
+       {"10", "%d", "10", 0},
+       {"10", "%v", "10", 0},
+       {"a", "%x", "10", 0},
+       {"0xa", "%v", "10", 0},
+       {"A", "%X", "10", 0},
+       {"-A", "%X", "-10", 0},
+       {"+0b1011001", "%v", "89", 0},
+       {"0xA", "%v", "10", 0},
+       {"0 ", "%v", "0", 1},
+       {"2+3", "%v", "2", 2},
+       {"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+       var buf bytes.Buffer
+       for i, test := range scanTests {
+               x := new(Int)
+               buf.Reset()
+               buf.WriteString(test.input)
+               if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+                       t.Errorf("#%d error: %s", i, err)
+               }
+               if x.String() != test.output {
+                       t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+               }
+               if buf.Len() != test.remaining {
+                       t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+               }
+       }
+}