mirror of
https://github.com/golang/go
synced 2024-11-20 01:04:40 -07:00
strconv: make Ftoa faster
Make code amenable to escape analysis so that the decimal values do not escape. benchmark old ns/op new ns/op delta strconv_test.BenchmarkAtof64Decimal 229 233 +1.75% strconv_test.BenchmarkAtof64Float 261 263 +0.77% strconv_test.BenchmarkAtof64FloatExp 7760 7757 -0.04% strconv_test.BenchmarkAtof64Big 3086 3053 -1.07% strconv_test.BenchmarkFtoa64Decimal 6866 2629 -61.71% strconv_test.BenchmarkFtoa64Float 7211 3064 -57.51% strconv_test.BenchmarkFtoa64FloatExp 12587 8263 -34.35% strconv_test.BenchmarkFtoa64Big 7058 2825 -59.97% json.BenchmarkCodeEncoder 357355200 276528200 -22.62% json.BenchmarkCodeMarshal 360735200 279646400 -22.48% json.BenchmarkCodeDecoder 731528600 709460600 -3.02% json.BenchmarkCodeUnmarshal 754774400 731051200 -3.14% json.BenchmarkCodeUnmarshalReuse 713379000 704218000 -1.28% json.BenchmarkSkipValue 51594300 51682600 +0.17% benchmark old MB/s new MB/s speedup json.BenchmarkCodeEncoder 5.43 7.02 1.29x json.BenchmarkCodeMarshal 5.38 6.94 1.29x json.BenchmarkCodeDecoder 2.65 2.74 1.03x json.BenchmarkCodeUnmarshal 2.57 2.65 1.03x json.BenchmarkCodeUnmarshalReuse 2.72 2.76 1.01x json.BenchmarkSkipValue 38.61 38.55 1.00x R=golang-dev, r CC=golang-dev https://golang.org/cl/5369111
This commit is contained in:
parent
94c2536e3f
commit
0ed5e6a2be
@ -102,12 +102,6 @@ func (a *decimal) Assign(v uint64) {
|
|||||||
trim(a)
|
trim(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDecimal(i uint64) *decimal {
|
|
||||||
a := new(decimal)
|
|
||||||
a.Assign(i)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maximum shift that we can do in one pass without overflow.
|
// Maximum shift that we can do in one pass without overflow.
|
||||||
// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
|
// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
|
||||||
const maxShift = 27
|
const maxShift = 27
|
||||||
@ -303,32 +297,32 @@ func shouldRoundUp(a *decimal, nd int) bool {
|
|||||||
// 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.
|
||||||
func (a *decimal) Round(nd int) *decimal {
|
func (a *decimal) Round(nd int) {
|
||||||
if nd < 0 || nd >= a.nd {
|
if nd < 0 || nd >= a.nd {
|
||||||
return a
|
return
|
||||||
}
|
}
|
||||||
if shouldRoundUp(a, nd) {
|
if shouldRoundUp(a, nd) {
|
||||||
return a.RoundUp(nd)
|
a.RoundUp(nd)
|
||||||
|
} else {
|
||||||
|
a.RoundDown(nd)
|
||||||
}
|
}
|
||||||
return a.RoundDown(nd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round a down to nd digits (or fewer).
|
// Round a down to nd digits (or fewer).
|
||||||
// Returns receiver for convenience.
|
// Returns receiver for convenience.
|
||||||
func (a *decimal) RoundDown(nd int) *decimal {
|
func (a *decimal) RoundDown(nd int) {
|
||||||
if nd < 0 || nd >= a.nd {
|
if nd < 0 || nd >= a.nd {
|
||||||
return a
|
return
|
||||||
}
|
}
|
||||||
a.nd = nd
|
a.nd = nd
|
||||||
trim(a)
|
trim(a)
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round a up to nd digits (or fewer).
|
// Round a up to nd digits (or fewer).
|
||||||
// Returns receiver for convenience.
|
// Returns receiver for convenience.
|
||||||
func (a *decimal) RoundUp(nd int) *decimal {
|
func (a *decimal) RoundUp(nd int) {
|
||||||
if nd < 0 || nd >= a.nd {
|
if nd < 0 || nd >= a.nd {
|
||||||
return a
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// round up
|
// round up
|
||||||
@ -337,7 +331,7 @@ func (a *decimal) RoundUp(nd int) *decimal {
|
|||||||
if c < '9' { // can stop after this digit
|
if c < '9' { // can stop after this digit
|
||||||
a.d[i]++
|
a.d[i]++
|
||||||
a.nd = i + 1
|
a.nd = i + 1
|
||||||
return a
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +340,6 @@ func (a *decimal) RoundUp(nd int) *decimal {
|
|||||||
a.d[0] = '1'
|
a.d[0] = '1'
|
||||||
a.nd = 1
|
a.nd = 1
|
||||||
a.dp++
|
a.dp++
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract integer part, rounded appropriately.
|
// Extract integer part, rounded appropriately.
|
||||||
|
@ -70,17 +70,23 @@ var roundtests = []roundTest{
|
|||||||
func TestDecimalRound(t *testing.T) {
|
func TestDecimalRound(t *testing.T) {
|
||||||
for i := 0; i < len(roundtests); i++ {
|
for i := 0; i < len(roundtests); i++ {
|
||||||
test := &roundtests[i]
|
test := &roundtests[i]
|
||||||
s := NewDecimal(test.i).RoundDown(test.nd).String()
|
d := NewDecimal(test.i)
|
||||||
|
d.RoundDown(test.nd)
|
||||||
|
s := d.String()
|
||||||
if s != test.down {
|
if s != test.down {
|
||||||
t.Errorf("Decimal %v RoundDown %d = %v, want %v",
|
t.Errorf("Decimal %v RoundDown %d = %v, want %v",
|
||||||
test.i, test.nd, s, test.down)
|
test.i, test.nd, s, test.down)
|
||||||
}
|
}
|
||||||
s = NewDecimal(test.i).Round(test.nd).String()
|
d = NewDecimal(test.i)
|
||||||
|
d.Round(test.nd)
|
||||||
|
s = d.String()
|
||||||
if s != test.round {
|
if s != test.round {
|
||||||
t.Errorf("Decimal %v Round %d = %v, want %v",
|
t.Errorf("Decimal %v Round %d = %v, want %v",
|
||||||
test.i, test.nd, s, test.down)
|
test.i, test.nd, s, test.down)
|
||||||
}
|
}
|
||||||
s = NewDecimal(test.i).RoundUp(test.nd).String()
|
d = NewDecimal(test.i)
|
||||||
|
d.RoundUp(test.nd)
|
||||||
|
s = d.String()
|
||||||
if s != test.up {
|
if s != test.up {
|
||||||
t.Errorf("Decimal %v RoundUp %d = %v, want %v",
|
t.Errorf("Decimal %v RoundUp %d = %v, want %v",
|
||||||
test.i, test.nd, s, test.up)
|
test.i, test.nd, s, test.up)
|
||||||
|
@ -98,7 +98,8 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
|
|||||||
// The shift is exp - flt.mantbits because mant is a 1-bit integer
|
// The shift is exp - flt.mantbits because mant is a 1-bit integer
|
||||||
// followed by a flt.mantbits fraction, and we are treating it as
|
// followed by a flt.mantbits fraction, and we are treating it as
|
||||||
// a 1+flt.mantbits-bit integer.
|
// a 1+flt.mantbits-bit integer.
|
||||||
d := newDecimal(mant)
|
d := new(decimal)
|
||||||
|
d.Assign(mant)
|
||||||
d.Shift(exp - int(flt.mantbits))
|
d.Shift(exp - int(flt.mantbits))
|
||||||
|
|
||||||
// Round appropriately.
|
// Round appropriately.
|
||||||
@ -184,7 +185,8 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
|
|||||||
// d = mant << (exp - mantbits)
|
// d = mant << (exp - mantbits)
|
||||||
// Next highest floating point number is mant+1 << exp-mantbits.
|
// Next highest floating point number is mant+1 << exp-mantbits.
|
||||||
// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
|
// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
|
||||||
upper := newDecimal(mant*2 + 1)
|
upper := new(decimal)
|
||||||
|
upper.Assign(mant*2 + 1)
|
||||||
upper.Shift(exp - int(flt.mantbits) - 1)
|
upper.Shift(exp - int(flt.mantbits) - 1)
|
||||||
|
|
||||||
// d = mant << (exp - mantbits)
|
// d = mant << (exp - mantbits)
|
||||||
@ -203,7 +205,8 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
|
|||||||
mantlo = mant*2 - 1
|
mantlo = mant*2 - 1
|
||||||
explo = exp - 1
|
explo = exp - 1
|
||||||
}
|
}
|
||||||
lower := newDecimal(mantlo*2 + 1)
|
lower := new(decimal)
|
||||||
|
lower.Assign(mantlo*2 + 1)
|
||||||
lower.Shift(explo - int(flt.mantbits) - 1)
|
lower.Shift(explo - int(flt.mantbits) - 1)
|
||||||
|
|
||||||
// The upper and lower bounds are possible outputs only if
|
// The upper and lower bounds are possible outputs only if
|
||||||
|
@ -6,7 +6,11 @@
|
|||||||
|
|
||||||
package strconv
|
package strconv
|
||||||
|
|
||||||
func NewDecimal(i uint64) *decimal { return newDecimal(i) }
|
func NewDecimal(i uint64) *decimal {
|
||||||
|
d := new(decimal)
|
||||||
|
d.Assign(i)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func SetOptimize(b bool) bool {
|
func SetOptimize(b bool) bool {
|
||||||
old := optimize
|
old := optimize
|
||||||
|
Loading…
Reference in New Issue
Block a user