mirror of
https://github.com/golang/go
synced 2024-11-19 23:04:40 -07:00
big: Improvements to Rat.SetString
* Allow an exponent part. This is necessary for exp/eval. * Fix a bug for input that had no numbers after the decimal. * In Int.SetString, allow a leading + sign. * In Int.SetString, error if the input is "-" with no number. * In nat.scan, normalize the resulting nat. R=gri CC=golang-dev https://golang.org/cl/1733045
This commit is contained in:
parent
56b3e5d644
commit
2e00bf9877
@ -347,10 +347,12 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
|
|||||||
return z, false
|
return z, false
|
||||||
}
|
}
|
||||||
|
|
||||||
neg := false
|
neg := s[0] == '-'
|
||||||
if s[0] == '-' {
|
if neg || s[0] == '+' {
|
||||||
neg = true
|
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
|
if len(s) == 0 {
|
||||||
|
return z, false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var scanned int
|
var scanned int
|
||||||
|
@ -219,6 +219,7 @@ var stringTests = []stringTest{
|
|||||||
stringTest{in: "a", ok: false},
|
stringTest{in: "a", ok: false},
|
||||||
stringTest{in: "z", ok: false},
|
stringTest{in: "z", ok: false},
|
||||||
stringTest{in: "+", ok: false},
|
stringTest{in: "+", ok: false},
|
||||||
|
stringTest{in: "-", ok: false},
|
||||||
stringTest{in: "0b", ok: false},
|
stringTest{in: "0b", ok: false},
|
||||||
stringTest{in: "0x", ok: false},
|
stringTest{in: "0x", ok: false},
|
||||||
stringTest{in: "2", base: 2, ok: false},
|
stringTest{in: "2", base: 2, ok: false},
|
||||||
@ -230,13 +231,17 @@ var stringTests = []stringTest{
|
|||||||
stringTest{"0", "0", 0, 0, true},
|
stringTest{"0", "0", 0, 0, true},
|
||||||
stringTest{"0", "0", 10, 0, true},
|
stringTest{"0", "0", 10, 0, true},
|
||||||
stringTest{"0", "0", 16, 0, true},
|
stringTest{"0", "0", 16, 0, true},
|
||||||
|
stringTest{"+0", "0", 0, 0, true},
|
||||||
|
stringTest{"-0", "0", 0, 0, true},
|
||||||
stringTest{"10", "10", 0, 10, true},
|
stringTest{"10", "10", 0, 10, true},
|
||||||
stringTest{"10", "10", 10, 10, true},
|
stringTest{"10", "10", 10, 10, true},
|
||||||
stringTest{"10", "10", 16, 16, true},
|
stringTest{"10", "10", 16, 16, true},
|
||||||
stringTest{"-10", "-10", 16, -16, true},
|
stringTest{"-10", "-10", 16, -16, true},
|
||||||
|
stringTest{"+10", "10", 16, 16, true},
|
||||||
stringTest{"0x10", "16", 0, 16, true},
|
stringTest{"0x10", "16", 0, 16, true},
|
||||||
stringTest{in: "0x10", base: 16, ok: false},
|
stringTest{in: "0x10", base: 16, ok: false},
|
||||||
stringTest{"-0x10", "-16", 0, -16, true},
|
stringTest{"-0x10", "-16", 0, -16, true},
|
||||||
|
stringTest{"+0x10", "16", 0, 16, true},
|
||||||
stringTest{"00", "0", 0, 0, true},
|
stringTest{"00", "0", 0, 0, true},
|
||||||
stringTest{"0", "0", 8, 0, true},
|
stringTest{"0", "0", 8, 0, true},
|
||||||
stringTest{"07", "7", 0, 7, true},
|
stringTest{"07", "7", 0, 7, true},
|
||||||
|
@ -103,9 +103,7 @@ func (z nat) setUint64(x uint64) nat {
|
|||||||
|
|
||||||
func (z nat) set(x nat) nat {
|
func (z nat) set(x nat) nat {
|
||||||
z = z.make(len(x))
|
z = z.make(len(x))
|
||||||
for i, d := range x {
|
copy(z, x)
|
||||||
z[i] = d
|
|
||||||
}
|
|
||||||
return z
|
return z
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +664,7 @@ func (z nat) scan(s string, base int) (nat, int, int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return z, base, i
|
return z.norm(), base, i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,26 +186,17 @@ func (z *Rat) Set(x *Rat) *Rat {
|
|||||||
|
|
||||||
|
|
||||||
// SetString sets z to the value of s and returns z and a boolean indicating
|
// SetString sets z to the value of s and returns z and a boolean indicating
|
||||||
// success. s can be given as a fraction "a/b" or as a decimal number "a.b".
|
// success. s can be given as a fraction "a/b" or as a floating-point number
|
||||||
// If the operation failed, the value of z is undefined.
|
// optionally followed by an exponent. If the operation failed, the value of z
|
||||||
|
// is undefined.
|
||||||
func (z *Rat) SetString(s string) (*Rat, bool) {
|
func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return z, false
|
return z, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a decimal point
|
// check for a quotient
|
||||||
sep := strings.Index(s, ".")
|
sep := strings.Index(s, "/")
|
||||||
if sep < 0 {
|
if sep >= 0 {
|
||||||
// Check for a quotient
|
|
||||||
sep = strings.Index(s, "/")
|
|
||||||
if sep < 0 {
|
|
||||||
// Just read in the string as an integer
|
|
||||||
if _, ok := z.a.SetString(s, 10); !ok {
|
|
||||||
return z, false
|
|
||||||
}
|
|
||||||
z.b = z.b.setWord(1)
|
|
||||||
return z, true
|
|
||||||
}
|
|
||||||
if _, ok := z.a.SetString(s[0:sep], 10); !ok {
|
if _, ok := z.a.SetString(s[0:sep], 10); !ok {
|
||||||
return z, false
|
return z, false
|
||||||
}
|
}
|
||||||
@ -214,17 +205,42 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
|
|||||||
if z.b, _, n = z.b.scan(s, 10); n != len(s) {
|
if z.b, _, n = z.b.scan(s, 10); n != len(s) {
|
||||||
return z, false
|
return z, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return z.norm(), true
|
return z.norm(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for a decimal point
|
||||||
|
sep = strings.Index(s, ".")
|
||||||
|
// check for an exponent
|
||||||
|
e := strings.IndexAny(s, "eE")
|
||||||
|
var exp Int
|
||||||
|
if e >= 0 {
|
||||||
|
if e < sep {
|
||||||
|
// The E must come after the decimal point.
|
||||||
|
return z, false
|
||||||
|
}
|
||||||
|
if _, ok := exp.SetString(s[e+1:], 10); !ok {
|
||||||
|
return z, false
|
||||||
|
}
|
||||||
|
s = s[0:e]
|
||||||
|
}
|
||||||
|
if sep >= 0 {
|
||||||
s = s[0:sep] + s[sep+1:]
|
s = s[0:sep] + s[sep+1:]
|
||||||
|
exp.Sub(&exp, NewInt(int64(len(s)-sep)))
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := z.a.SetString(s, 10); !ok {
|
if _, ok := z.a.SetString(s, 10); !ok {
|
||||||
return z, false
|
return z, false
|
||||||
}
|
}
|
||||||
z.b = z.b.expNN(natTen, nat{Word(len(s) - sep)}, nil)
|
powTen := nat{}.expNN(natTen, exp.abs, nil)
|
||||||
|
if exp.neg {
|
||||||
|
z.b = powTen
|
||||||
|
z.norm()
|
||||||
|
} else {
|
||||||
|
z.a.abs = z.a.abs.mul(z.a.abs, powTen)
|
||||||
|
z.b = z.b.setWord(1)
|
||||||
|
}
|
||||||
|
|
||||||
return z.norm(), true
|
return z, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -257,7 +273,7 @@ func (z *Rat) FloatString(prec int) string {
|
|||||||
r = r.mul(r, p)
|
r = r.mul(r, p)
|
||||||
r, r2 := r.div(nat{}, r, z.b)
|
r, r2 := r.div(nat{}, r, z.b)
|
||||||
|
|
||||||
// See if we need to round up
|
// see if we need to round up
|
||||||
r2 = r2.mul(r2, natTwo)
|
r2 = r2.mul(r2, natTwo)
|
||||||
if z.b.cmp(r2) <= 0 {
|
if z.b.cmp(r2) <= 0 {
|
||||||
r = r.add(r, natOne)
|
r = r.add(r, natOne)
|
||||||
|
@ -17,6 +17,13 @@ var setStringTests = []setStringTest{
|
|||||||
setStringTest{"-0", "0", true},
|
setStringTest{"-0", "0", true},
|
||||||
setStringTest{"1", "1", true},
|
setStringTest{"1", "1", true},
|
||||||
setStringTest{"-1", "-1", true},
|
setStringTest{"-1", "-1", true},
|
||||||
|
setStringTest{"1.", "1", true},
|
||||||
|
setStringTest{"1e0", "1", true},
|
||||||
|
setStringTest{"1.e1", "10", true},
|
||||||
|
setStringTest{in: "1e", ok: false},
|
||||||
|
setStringTest{in: "1.e", ok: false},
|
||||||
|
setStringTest{in: "1e+14e-5", ok: false},
|
||||||
|
setStringTest{in: "1e4.5", ok: false},
|
||||||
setStringTest{in: "r", ok: false},
|
setStringTest{in: "r", ok: false},
|
||||||
setStringTest{in: "a/b", ok: false},
|
setStringTest{in: "a/b", ok: false},
|
||||||
setStringTest{in: "a.b", ok: false},
|
setStringTest{in: "a.b", ok: false},
|
||||||
@ -25,6 +32,12 @@ var setStringTests = []setStringTest{
|
|||||||
setStringTest{"2/4", "1/2", true},
|
setStringTest{"2/4", "1/2", true},
|
||||||
setStringTest{".25", "1/4", true},
|
setStringTest{".25", "1/4", true},
|
||||||
setStringTest{"-1/5", "-1/5", true},
|
setStringTest{"-1/5", "-1/5", true},
|
||||||
|
setStringTest{"8129567.7690E14", "812956776900000000000", true},
|
||||||
|
setStringTest{"78189e+4", "781890000", true},
|
||||||
|
setStringTest{"553019.8935e+8", "55301989350000", true},
|
||||||
|
setStringTest{"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
|
||||||
|
setStringTest{"9877861857500000E-7", "3951144743/4", true},
|
||||||
|
setStringTest{"2169378.417e-3", "2169378417/1000000", true},
|
||||||
setStringTest{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
|
setStringTest{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
|
||||||
setStringTest{"53/70893980658822810696", "53/70893980658822810696", true},
|
setStringTest{"53/70893980658822810696", "53/70893980658822810696", true},
|
||||||
setStringTest{"106/141787961317645621392", "53/70893980658822810696", true},
|
setStringTest{"106/141787961317645621392", "53/70893980658822810696", true},
|
||||||
|
Loading…
Reference in New Issue
Block a user