1
0
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:
Russ Cox 2011-11-15 12:17:25 -05:00
parent 94c2536e3f
commit 0ed5e6a2be
4 changed files with 30 additions and 24 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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