mirror of
https://github.com/golang/go
synced 2024-11-25 08:57:58 -07:00
big: support %v and # modifier, better handling of unknown formats
R=r CC=golang-dev https://golang.org/cl/4536065
This commit is contained in:
parent
8e26a644ca
commit
82ddf97094
@ -309,11 +309,13 @@ func (x *Int) Cmp(y *Int) (r int) {
|
|||||||
|
|
||||||
|
|
||||||
func (x *Int) String() string {
|
func (x *Int) String() string {
|
||||||
s := ""
|
switch {
|
||||||
if x.neg {
|
case x == nil:
|
||||||
s = "-"
|
return "<nil>"
|
||||||
|
case x.neg:
|
||||||
|
return "-" + x.abs.decimalString()
|
||||||
}
|
}
|
||||||
return s + x.abs.decimalString()
|
return x.abs.decimalString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -323,7 +325,7 @@ func charset(ch int) string {
|
|||||||
return lowercaseDigits[0:2]
|
return lowercaseDigits[0:2]
|
||||||
case 'o':
|
case 'o':
|
||||||
return lowercaseDigits[0:8]
|
return lowercaseDigits[0:8]
|
||||||
case 'd':
|
case 'd', 'v':
|
||||||
return lowercaseDigits[0:10]
|
return lowercaseDigits[0:10]
|
||||||
case 'x':
|
case 'x':
|
||||||
return lowercaseDigits[0:16]
|
return lowercaseDigits[0:16]
|
||||||
@ -339,14 +341,36 @@ func charset(ch int) string {
|
|||||||
// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
|
// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
|
||||||
//
|
//
|
||||||
func (x *Int) Format(s fmt.State, ch int) {
|
func (x *Int) Format(s fmt.State, ch int) {
|
||||||
if x == nil {
|
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>")
|
fmt.Fprint(s, "<nil>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if x.neg {
|
|
||||||
fmt.Fprint(s, "-")
|
// determine format
|
||||||
|
format := "%s"
|
||||||
|
if s.Flag('#') {
|
||||||
|
switch ch {
|
||||||
|
case 'o':
|
||||||
|
format = "0%s"
|
||||||
|
case 'x':
|
||||||
|
format = "0x%s"
|
||||||
|
case 'X':
|
||||||
|
format = "0X%s"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprint(s, x.abs.string(charset(ch)))
|
if x.neg {
|
||||||
|
format = "-" + format
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(s, format, x.abs.string(cs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -348,6 +348,55 @@ func TestSetString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 %s; want %s", i, output, test.output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Examples from the Go Language Spec, section "Arithmetic operators"
|
// Examples from the Go Language Spec, section "Arithmetic operators"
|
||||||
var divisionSignsTests = []struct {
|
var divisionSignsTests = []struct {
|
||||||
x, y int64
|
x, y int64
|
||||||
@ -984,6 +1033,7 @@ func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func altBit(x *Int, i int) uint {
|
func altBit(x *Int, i int) uint {
|
||||||
z := new(Int).Rsh(x, uint(i))
|
z := new(Int).Rsh(x, uint(i))
|
||||||
z = z.And(z, NewInt(1))
|
z = z.And(z, NewInt(1))
|
||||||
@ -993,6 +1043,7 @@ func altBit(x *Int, i int) uint {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func altSetBit(z *Int, x *Int, i int, b uint) *Int {
|
func altSetBit(z *Int, x *Int, i int, b uint) *Int {
|
||||||
one := NewInt(1)
|
one := NewInt(1)
|
||||||
m := one.Lsh(one, uint(i))
|
m := one.Lsh(one, uint(i))
|
||||||
@ -1005,6 +1056,7 @@ func altSetBit(z *Int, x *Int, i int, b uint) *Int {
|
|||||||
panic("set bit is not 0 or 1")
|
panic("set bit is not 0 or 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func testBitset(t *testing.T, x *Int) {
|
func testBitset(t *testing.T, x *Int) {
|
||||||
n := x.BitLen()
|
n := x.BitLen()
|
||||||
z := new(Int).Set(x)
|
z := new(Int).Set(x)
|
||||||
@ -1042,6 +1094,7 @@ func testBitset(t *testing.T, x *Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var bitsetTests = []struct {
|
var bitsetTests = []struct {
|
||||||
x string
|
x string
|
||||||
i int
|
i int
|
||||||
@ -1061,6 +1114,7 @@ var bitsetTests = []struct {
|
|||||||
{"-0x2000000000000000000000000001", 110, 1},
|
{"-0x2000000000000000000000000001", 110, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestBitSet(t *testing.T) {
|
func TestBitSet(t *testing.T) {
|
||||||
for _, test := range bitwiseTests {
|
for _, test := range bitwiseTests {
|
||||||
x := new(Int)
|
x := new(Int)
|
||||||
@ -1081,6 +1135,7 @@ func TestBitSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func BenchmarkBitset(b *testing.B) {
|
func BenchmarkBitset(b *testing.B) {
|
||||||
z := new(Int)
|
z := new(Int)
|
||||||
z.SetBit(z, 512, 1)
|
z.SetBit(z, 512, 1)
|
||||||
@ -1091,6 +1146,7 @@ func BenchmarkBitset(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func BenchmarkBitsetNeg(b *testing.B) {
|
func BenchmarkBitsetNeg(b *testing.B) {
|
||||||
z := NewInt(-1)
|
z := NewInt(-1)
|
||||||
z.SetBit(z, 512, 0)
|
z.SetBit(z, 512, 0)
|
||||||
@ -1101,6 +1157,7 @@ func BenchmarkBitsetNeg(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func BenchmarkBitsetOrig(b *testing.B) {
|
func BenchmarkBitsetOrig(b *testing.B) {
|
||||||
z := new(Int)
|
z := new(Int)
|
||||||
altSetBit(z, z, 512, 1)
|
altSetBit(z, z, 512, 1)
|
||||||
@ -1111,6 +1168,7 @@ func BenchmarkBitsetOrig(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func BenchmarkBitsetNegOrig(b *testing.B) {
|
func BenchmarkBitsetNegOrig(b *testing.B) {
|
||||||
z := NewInt(-1)
|
z := NewInt(-1)
|
||||||
altSetBit(z, z, 512, 0)
|
altSetBit(z, z, 512, 0)
|
||||||
@ -1121,6 +1179,7 @@ func BenchmarkBitsetNegOrig(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestBitwise(t *testing.T) {
|
func TestBitwise(t *testing.T) {
|
||||||
x := new(Int)
|
x := new(Int)
|
||||||
y := new(Int)
|
y := new(Int)
|
||||||
@ -1155,6 +1214,7 @@ var notTests = []struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestNot(t *testing.T) {
|
func TestNot(t *testing.T) {
|
||||||
in := new(Int)
|
in := new(Int)
|
||||||
out := new(Int)
|
out := new(Int)
|
||||||
@ -1183,6 +1243,7 @@ var modInverseTests = []struct {
|
|||||||
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
|
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestModInverse(t *testing.T) {
|
func TestModInverse(t *testing.T) {
|
||||||
var element, prime Int
|
var element, prime Int
|
||||||
one := NewInt(1)
|
one := NewInt(1)
|
||||||
|
@ -677,13 +677,14 @@ const (
|
|||||||
|
|
||||||
// string converts x to a string using digits from a charset; a digit with
|
// string converts x to a string using digits from a charset; a digit with
|
||||||
// value d is represented by charset[d]. The conversion base is determined
|
// value d is represented by charset[d]. The conversion base is determined
|
||||||
// by len(charset). If len(charset) < 2, the result is "<illegal base>".
|
// by len(charset), which must be >= 2.
|
||||||
func (x nat) string(charset string) string {
|
func (x nat) string(charset string) string {
|
||||||
base := len(charset)
|
base := len(charset)
|
||||||
|
|
||||||
|
// special cases
|
||||||
switch {
|
switch {
|
||||||
case base < 2:
|
case base < 2:
|
||||||
return "<illegal base>"
|
panic("illegal base")
|
||||||
case len(x) == 0:
|
case len(x) == 0:
|
||||||
return string(charset[0])
|
return string(charset[0])
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user