mirror of
https://github.com/golang/go
synced 2024-11-25 12:57:58 -07:00
strconv: handle very large inputs
Fixes #2642. R=remyoudompheng, r, r CC=golang-dev https://golang.org/cl/5639052
This commit is contained in:
parent
00134fe8ef
commit
3ee208533e
@ -52,10 +52,10 @@ func special(s string) (f float64, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rsc): Better truncation handling.
|
|
||||||
func (b *decimal) set(s string) (ok bool) {
|
func (b *decimal) set(s string) (ok bool) {
|
||||||
i := 0
|
i := 0
|
||||||
b.neg = false
|
b.neg = false
|
||||||
|
b.trunc = false
|
||||||
|
|
||||||
// optional sign
|
// optional sign
|
||||||
if i >= len(s) {
|
if i >= len(s) {
|
||||||
@ -88,8 +88,12 @@ func (b *decimal) set(s string) (ok bool) {
|
|||||||
b.dp--
|
b.dp--
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.d[b.nd] = s[i]
|
if b.nd < len(b.d) {
|
||||||
b.nd++
|
b.d[b.nd] = s[i]
|
||||||
|
b.nd++
|
||||||
|
} else if s[i] != '0' {
|
||||||
|
b.trunc = true
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
. "strconv"
|
. "strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -117,6 +118,20 @@ var atoftests = []atofTest{
|
|||||||
|
|
||||||
// A very large number (initially wrongly parsed by the fast algorithm).
|
// A very large number (initially wrongly parsed by the fast algorithm).
|
||||||
{"4.630813248087435e+307", "4.630813248087435e+307", nil},
|
{"4.630813248087435e+307", "4.630813248087435e+307", nil},
|
||||||
|
|
||||||
|
// A different kind of very large number.
|
||||||
|
{"22.222222222222222", "22.22222222222222", nil},
|
||||||
|
{"2." + strings.Repeat("2", 4000) + "e+1", "22.22222222222222", nil},
|
||||||
|
|
||||||
|
// Exactly halfway between 1 and math.Nextafter(1, 2).
|
||||||
|
// Round to even (down).
|
||||||
|
{"1.00000000000000011102230246251565404236316680908203125", "1", nil},
|
||||||
|
// Slightly lower; still round down.
|
||||||
|
{"1.00000000000000011102230246251565404236316680908203124", "1", nil},
|
||||||
|
// Slightly higher; round up.
|
||||||
|
{"1.00000000000000011102230246251565404236316680908203126", "1.0000000000000002", nil},
|
||||||
|
// Slightly higher, but you have to read all the way to the end.
|
||||||
|
{"1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", "1.0000000000000002", nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
type atofSimpleTest struct {
|
type atofSimpleTest struct {
|
||||||
|
@ -12,12 +12,11 @@
|
|||||||
package strconv
|
package strconv
|
||||||
|
|
||||||
type decimal struct {
|
type decimal struct {
|
||||||
// TODO(rsc): Can make d[] a bit smaller and add
|
d [800]byte // digits
|
||||||
// truncated bool;
|
nd int // number of digits used
|
||||||
d [800]byte // digits
|
dp int // decimal point
|
||||||
nd int // number of digits used
|
neg bool
|
||||||
dp int // decimal point
|
trunc bool // discarded nonzero digits beyond d[:nd]
|
||||||
neg bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *decimal) String() string {
|
func (a *decimal) String() string {
|
||||||
@ -145,8 +144,12 @@ func rightShift(a *decimal, k uint) {
|
|||||||
for n > 0 {
|
for n > 0 {
|
||||||
dig := n >> k
|
dig := n >> k
|
||||||
n -= dig << k
|
n -= dig << k
|
||||||
a.d[w] = byte(dig + '0')
|
if w < len(a.d) {
|
||||||
w++
|
a.d[w] = byte(dig + '0')
|
||||||
|
w++
|
||||||
|
} else if dig > 0 {
|
||||||
|
a.trunc = true
|
||||||
|
}
|
||||||
n = n * 10
|
n = n * 10
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +245,11 @@ func leftShift(a *decimal, k uint) {
|
|||||||
quo := n / 10
|
quo := n / 10
|
||||||
rem := n - 10*quo
|
rem := n - 10*quo
|
||||||
w--
|
w--
|
||||||
a.d[w] = byte(rem + '0')
|
if w < len(a.d) {
|
||||||
|
a.d[w] = byte(rem + '0')
|
||||||
|
} else if rem != 0 {
|
||||||
|
a.trunc = true
|
||||||
|
}
|
||||||
n = quo
|
n = quo
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,11 +258,18 @@ func leftShift(a *decimal, k uint) {
|
|||||||
quo := n / 10
|
quo := n / 10
|
||||||
rem := n - 10*quo
|
rem := n - 10*quo
|
||||||
w--
|
w--
|
||||||
a.d[w] = byte(rem + '0')
|
if w < len(a.d) {
|
||||||
|
a.d[w] = byte(rem + '0')
|
||||||
|
} else if rem != 0 {
|
||||||
|
a.trunc = true
|
||||||
|
}
|
||||||
n = quo
|
n = quo
|
||||||
}
|
}
|
||||||
|
|
||||||
a.nd += delta
|
a.nd += delta
|
||||||
|
if a.nd >= len(a.d) {
|
||||||
|
a.nd = len(a.d)
|
||||||
|
}
|
||||||
a.dp += delta
|
a.dp += delta
|
||||||
trim(a)
|
trim(a)
|
||||||
}
|
}
|
||||||
@ -286,6 +300,10 @@ func shouldRoundUp(a *decimal, nd int) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
|
if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
|
||||||
|
// if we truncated, a little higher than what's recorded - always round up
|
||||||
|
if a.trunc {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return nd > 0 && (a.d[nd-1]-'0')%2 != 0
|
return nd > 0 && (a.d[nd-1]-'0')%2 != 0
|
||||||
}
|
}
|
||||||
// not halfway - digit tells all
|
// not halfway - digit tells all
|
||||||
@ -293,7 +311,6 @@ func shouldRoundUp(a *decimal, nd int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Round a to nd digits (or fewer).
|
// Round a to nd digits (or fewer).
|
||||||
// Returns receiver for convenience.
|
|
||||||
// If nd is zero, it means we're rounding
|
// If nd is zero, it means we're rounding
|
||||||
// just to the left of the digits, as in
|
// just to the left of the digits, as in
|
||||||
// 0.09 -> 0.1.
|
// 0.09 -> 0.1.
|
||||||
@ -309,7 +326,6 @@ func (a *decimal) Round(nd int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Round a down to nd digits (or fewer).
|
// Round a down to nd digits (or fewer).
|
||||||
// Returns receiver for convenience.
|
|
||||||
func (a *decimal) RoundDown(nd int) {
|
func (a *decimal) RoundDown(nd int) {
|
||||||
if nd < 0 || nd >= a.nd {
|
if nd < 0 || nd >= a.nd {
|
||||||
return
|
return
|
||||||
@ -319,7 +335,6 @@ func (a *decimal) RoundDown(nd int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Round a up to nd digits (or fewer).
|
// Round a up to nd digits (or fewer).
|
||||||
// Returns receiver for convenience.
|
|
||||||
func (a *decimal) RoundUp(nd int) {
|
func (a *decimal) RoundUp(nd int) {
|
||||||
if nd < 0 || nd >= a.nd {
|
if nd < 0 || nd >= a.nd {
|
||||||
return
|
return
|
||||||
|
Loading…
Reference in New Issue
Block a user