]> Cypherpunks repositories - gostls13.git/commitdiff
strconv: make Ftoa faster
authorRuss Cox <rsc@golang.org>
Tue, 15 Nov 2011 17:17:25 +0000 (12:17 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 15 Nov 2011 17:17:25 +0000 (12:17 -0500)
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

src/pkg/strconv/decimal.go
src/pkg/strconv/decimal_test.go
src/pkg/strconv/ftoa.go
src/pkg/strconv/internal_test.go

index f572ea4a22d5056e07ad0b22cd867180f9866a78..541553097bbb3a2e9fcb1449bc2cc34710693277 100644 (file)
@@ -102,12 +102,6 @@ func (a *decimal) Assign(v uint64) {
        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.
 // Signed int has 31 bits, and we have to be able to accommodate 9<<k.
 const maxShift = 27
@@ -303,32 +297,32 @@ func shouldRoundUp(a *decimal, nd int) bool {
 // If nd is zero, it means we're rounding
 // just to the left of the digits, as in
 // 0.09 -> 0.1.
-func (a *decimal) Round(nd int) *decimal {
+func (a *decimal) Round(nd int) {
        if nd < 0 || nd >= a.nd {
-               return a
+               return
        }
        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).
 // Returns receiver for convenience.
-func (a *decimal) RoundDown(nd int) *decimal {
+func (a *decimal) RoundDown(nd int) {
        if nd < 0 || nd >= a.nd {
-               return a
+               return
        }
        a.nd = nd
        trim(a)
-       return a
 }
 
 // Round a up to nd digits (or fewer).
 // Returns receiver for convenience.
-func (a *decimal) RoundUp(nd int) *decimal {
+func (a *decimal) RoundUp(nd int) {
        if nd < 0 || nd >= a.nd {
-               return a
+               return
        }
 
        // round up
@@ -337,7 +331,7 @@ func (a *decimal) RoundUp(nd int) *decimal {
                if c < '9' { // can stop after this digit
                        a.d[i]++
                        a.nd = i + 1
-                       return a
+                       return
                }
        }
 
@@ -346,7 +340,6 @@ func (a *decimal) RoundUp(nd int) *decimal {
        a.d[0] = '1'
        a.nd = 1
        a.dp++
-       return a
 }
 
 // Extract integer part, rounded appropriately.
index deb2e02f6108478e9f64270faf0abdb775d24222..13a127f5b2cfc9a1123a86d2711132ca69555891 100644 (file)
@@ -70,17 +70,23 @@ var roundtests = []roundTest{
 func TestDecimalRound(t *testing.T) {
        for i := 0; i < len(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 {
                        t.Errorf("Decimal %v RoundDown %d = %v, want %v",
                                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 {
                        t.Errorf("Decimal %v Round %d = %v, want %v",
                                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 {
                        t.Errorf("Decimal %v RoundUp %d = %v, want %v",
                                test.i, test.nd, s, test.up)
index 07fe806b97dec2cdf3ea724a5ef594ec26f7546c..8342b6abe79494db82e085a377396e3479518c6b 100644 (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
        // followed by a flt.mantbits fraction, and we are treating it as
        // a 1+flt.mantbits-bit integer.
-       d := newDecimal(mant)
+       d := new(decimal)
+       d.Assign(mant)
        d.Shift(exp - int(flt.mantbits))
 
        // Round appropriately.
@@ -184,7 +185,8 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
        // d = mant << (exp - mantbits)
        // Next highest floating point number is mant+1 << exp-mantbits.
        // 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)
 
        // d = mant << (exp - mantbits)
@@ -203,7 +205,8 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
                mantlo = mant*2 - 1
                explo = exp - 1
        }
-       lower := newDecimal(mantlo*2 + 1)
+       lower := new(decimal)
+       lower.Assign(mantlo*2 + 1)
        lower.Shift(explo - int(flt.mantbits) - 1)
 
        // The upper and lower bounds are possible outputs only if
index 9a7f4f0867c5d53f79fe007e4364491ec4d186a9..d0fa80edfb6f9a7f2a66535405111c313ef863ce 100644 (file)
@@ -6,7 +6,11 @@
 
 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 {
        old := optimize