From 06e9fdfdf13bdee7328295593504cc5ec86f6e8b Mon Sep 17 00:00:00 2001 From: Caleb Spare Date: Sat, 12 Jan 2019 16:20:56 -0800 Subject: [PATCH] Remove the digit table optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The benefit was fairly marginal. We can get some of it by doing only the "avoid 64-bit divisions" optimization and not take the size hit. name old time/op new time/op delta AppendFloat64/0e+00-12 3.30ns ± 2% 3.30ns ± 1% ~ (p=0.881 n=5+5) AppendFloat64/1e+00-12 15.3ns ± 1% 15.3ns ± 1% ~ (p=0.635 n=5+5) AppendFloat64/3e-01-12 50.0ns ± 1% 50.8ns ± 1% +1.44% (p=0.016 n=5+5) AppendFloat64/1e+06-12 20.8ns ± 1% 21.2ns ± 1% +2.02% (p=0.024 n=5+5) AppendFloat64/-1.2345e+02-12 49.5ns ± 1% 50.0ns ± 1% +1.01% (p=0.032 n=5+5) AppendFloat64/6.226662346353213e-309-12 39.1ns ± 1% 41.4ns ± 2% +5.89% (p=0.008 n=5+5) --- maketables.go | 9 --------- ryu.go | 5 ----- ryu32.go | 1 - ryu64.go | 54 +++++++++++---------------------------------------- tables.go | 13 ------------- 5 files changed, 11 insertions(+), 71 deletions(-) diff --git a/maketables.go b/maketables.go index 50f00bb..4625eef 100644 --- a/maketables.go +++ b/maketables.go @@ -75,15 +75,6 @@ const ( func main() { b := bytes.NewBuffer(header) - fmt.Fprintln(b, "var twoDigits = [200]byte{") - for i := 0; i < 10; i++ { - for j := 0; j < 10; j++ { - fmt.Fprintf(b, "'%c','%c',", '0'+i, '0'+j) - } - fmt.Fprintln(b) - } - fmt.Fprintln(b, "\n}") - fmt.Fprintf(b, "const pow5NumBits32 = %d\n", pow5NumBits32) fmt.Fprintln(b, "var pow5Split32 = [...]uint64{") for i := int64(0); i < posTableSize32; i++ { diff --git a/ryu.go b/ryu.go index aeebfa7..89518e5 100644 --- a/ryu.go +++ b/ryu.go @@ -161,11 +161,6 @@ func pow5Bits(e int32) int32 { return int32((uint32(e)*1217359)>>19 + 1) } -func copyTwoDigits(b []byte, d uint) { - b[0] = twoDigits[d] - b[1] = twoDigits[d+1] -} - // FIXME(caleb): Document how these are optimized. func boolToUint32(b bool) uint32 { diff --git a/ryu32.go b/ryu32.go index f22c6d0..61cf8ec 100644 --- a/ryu32.go +++ b/ryu32.go @@ -42,7 +42,6 @@ func (d dec32) append(b []byte, neg bool) []byte { } // Print the decimal digits. - // FIXME: optimize n := len(b) b = append(b, make([]byte, bufLen)...) for i := 0; i < outLen-1; i++ { diff --git a/ryu64.go b/ryu64.go index 0fc3f57..5008bb8 100644 --- a/ryu64.go +++ b/ryu64.go @@ -53,59 +53,27 @@ func (d dec64) append(b []byte, neg bool) []byte { } else { b = append(b, make([]byte, bufLen)...) } - // The code below is equivalent to the following: - // for i := 0; i < outLen-1; i++ { - // b[n+outLen-i] = '0' + byte(out%10) - // out /= 10 - // } - // b[n] = '0' + byte(out%10) - // We prefer 32-bit divisions even on 64-bit platforms. + // Avoid expensive 64-bit divisions. // We have at most 17 digits, and uint32 can store 9 digits. // If the output doesn't fit into a uint32, cut off 8 digits // so the rest will fit into a uint32. var i int if out>>32 > 0 { // FIXME: bits.Div? - q, r := out/1e8, out%1e8 - out = q - - c := r % 1e4 - r /= 1e4 - d := r % 1e4 - c0 := uint(c%100) << 1 - c1 := uint(c/100) << 1 - d0 := uint(d%100) << 1 - d1 := uint(d/100) << 1 - copyTwoDigits(b[n+outLen-i-7:], d1) - copyTwoDigits(b[n+outLen-i-5:], d0) - copyTwoDigits(b[n+outLen-i-3:], c1) - copyTwoDigits(b[n+outLen-i-1:], c0) - i += 8 + var out32 uint32 + out, out32 = out/1e8, uint32(out%1e8) + for ; i < 8; i++ { + b[n+outLen-i] = '0' + byte(out32%10) + out32 /= 10 + } } out32 := uint32(out) - for ; out32 >= 1e4; i += 4 { - c := out32 % 1e4 - out32 /= 1e4 - c0 := uint(c%100) << 1 - c1 := uint(c/100) << 1 - copyTwoDigits(b[n+outLen-i-1:], c0) - copyTwoDigits(b[n+outLen-i-3:], c1) - } - if out32 >= 100 { - c := uint(out32%100) << 1 - out32 /= 100 - copyTwoDigits(b[n+outLen-i-1:], c) - i += 2 - } - if out32 >= 10 { - c := out32 << 1 - // The dot goes between the digits. - b[n+outLen-i] = twoDigits[c+1] - b[n] = twoDigits[c] - } else { - b[n] = '0' + byte(out32) + for ; i < outLen-1; i++ { + b[n+outLen-i] = '0' + byte(out32%10) + out32 /= 10 } + b[n] = '0' + byte(out32%10) // Print the '.' if needed. if outLen > 1 { diff --git a/tables.go b/tables.go index 11c8330..fe33ad9 100644 --- a/tables.go +++ b/tables.go @@ -19,19 +19,6 @@ package ryu -var twoDigits = [200]byte{ - '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', - '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', - '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', - '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', - '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', - '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', - '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', - '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', - '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', - '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9', -} - const pow5NumBits32 = 61 var pow5Split32 = [...]uint64{