Skip to content

Commit

Permalink
Merge pull request #125 from miretskiy/decimal
Browse files Browse the repository at this point in the history
apd: Improve string conversion efficiency
  • Loading branch information
miretskiy authored Oct 17, 2022
2 parents e2030eb + 9d47f6a commit e2bc4ac
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 10 deletions.
29 changes: 24 additions & 5 deletions bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import (
// runBenches benchmarks a given function on random decimals on combinations of
// three parameters:
//
// precision: desired output precision
// inScale: the scale of the input decimal: the absolute value will be between
// 10^inScale and 10^(inScale+1)
// inNumDigits: number of digits in the input decimal; if negative the number
// will be negative and the number of digits are the absolute value.
// precision: desired output precision
// inScale: the scale of the input decimal: the absolute value will be between
// 10^inScale and 10^(inScale+1)
// inNumDigits: number of digits in the input decimal; if negative the number
// will be negative and the number of digits are the absolute value.
func runBenches(
b *testing.B, precision, inScale, inNumDigits []int, fn func(*testing.B, *Context, *Decimal),
) {
Expand Down Expand Up @@ -103,3 +103,22 @@ func BenchmarkLn(b *testing.B) {
},
)
}

func BenchmarkDecimalString(b *testing.B) {
rng := rand.New(rand.NewSource(461210934723948))
corpus := func() []Decimal {
res := make([]Decimal, 8192)
for i := range res {
_, err := res[i].SetFloat64(rng.Float64())
if err != nil {
b.Fatal(err)
}
}
return res
}()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = corpus[rng.Intn(len(corpus))].String()
}
}
11 changes: 6 additions & 5 deletions format.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
// zeros (the 'g' format avoids the use of 'f' in this case). All other
// formats always show the exact precision of the Decimal.
func (d *Decimal) Text(format byte) string {
cap := 10 // TODO(gri) determine a good/better value here
return string(d.Append(make([]byte, 0, cap), format))
var buf [16]byte
return string(d.Append(buf[:0], format))
}

// String formats x like x.Text('G'). It matches the to-scientific-string
Expand Down Expand Up @@ -57,7 +57,8 @@ func (d *Decimal) Append(buf []byte, fmt byte) []byte {
return append(buf, "unknown"...)
}

digits := d.Coeff.String()
var scratch [16]byte
digits := d.Coeff.Append(scratch[:0], 10)
switch fmt {
case 'e', 'E':
return fmtE(buf, fmt, d, digits)
Expand All @@ -83,7 +84,7 @@ func (d *Decimal) Append(buf []byte, fmt byte) []byte {
}

// %e: d.ddddde±d
func fmtE(buf []byte, fmt byte, d *Decimal, digits string) []byte {
func fmtE(buf []byte, fmt byte, d *Decimal, digits []byte) []byte {
adj := int64(d.Exponent) + int64(len(digits)) - 1
buf = append(buf, digits[0])
if len(digits) > 1 {
Expand All @@ -103,7 +104,7 @@ func fmtE(buf []byte, fmt byte, d *Decimal, digits string) []byte {
}

// %f: ddddddd.ddddd
func fmtF(buf []byte, d *Decimal, digits string) []byte {
func fmtF(buf []byte, d *Decimal, digits []byte) []byte {
if d.Exponent < 0 {
if left := -int(d.Exponent) - len(digits); left >= 0 {
buf = append(buf, "0."...)
Expand Down

0 comments on commit e2bc4ac

Please sign in to comment.