strconv: optimize int-to-decimal and use consistently

Integer-to-decimal conversion is hand-written in multiple
places in this package, with different incomplete optimizations
in  different copies. This CL establishes a single implementation,
formatBase10, accurately optimized for a variety of systems,
and then uses it consistently.

Removed the fastSmalls const, which has been true since 2017.
Also renamed smallsString to smalls.

benchmark \ host                    local  linux-arm64       s7  linux-amd64  linux-ppc64le  linux-s390x  linux-arm  s7:GOARCH=386  linux-386
                                  vs base      vs base  vs base      vs base        vs base      vs base    vs base        vs base    vs base
AppendFloat/Decimal                     ~            ~        ~            ~              ~            ~     +0.99%              ~          ~
AppendFloat/Float                       ~            ~        ~       +2.67%              ~            ~     -0.17%              ~          ~
AppendFloat/Exp                         ~            ~        ~            ~         -5.01%       -0.88%     -0.14%              ~          ~
AppendFloat/NegExp                      ~            ~        ~       +1.80%              ~       -1.55%     -0.67%              ~          ~
AppendFloat/LongExp                     ~            ~        ~       -1.36%         -2.34%            ~     +0.41%              ~          ~
AppendFloat/Big                         ~            ~        ~       -3.94%         -2.66%       -0.61%     +1.01%              ~          ~
AppendFloat/BinaryExp              -5.86%       -2.20%   -3.27%      -17.16%         -6.89%            ~    -61.81%        -33.80%    -27.61%
AppendFloat/32Integer                   ~            ~        ~            ~              ~            ~     +0.74%              ~          ~
AppendFloat/32ExactFraction             ~            ~        ~       +2.96%              ~            ~     +0.09%         +1.62%          ~
AppendFloat/32Point                     ~            ~        ~            ~              ~            ~     +1.31%              ~          ~
AppendFloat/32Exp                       ~            ~        ~            ~         -4.05%            ~     -0.05%              ~          ~
AppendFloat/32NegExp                    ~            ~        ~       -0.86%         -4.97%            ~     +0.23%              ~          ~
AppendFloat/32Shortest                  ~            ~        ~            ~              ~            ~     +0.72%              ~          ~
AppendFloat/32Fixed8Hard           +4.58%       +1.94%   +2.77%       -4.39%              ~       +4.39%     -9.36%        -11.97%    -15.71%
AppendFloat/32Fixed9Hard           +4.52%       +5.41%   +4.13%       +3.10%         -4.84%      +14.34%     -3.83%         -1.84%     -6.42%
AppendFloat/64Fixed1               +3.37%       +3.45%   +1.31%            ~         +6.93%       +4.79%     -2.99%         -2.07%     -5.51%
AppendFloat/64Fixed2               +3.44%       +3.46%   +0.80%            ~         +6.03%       +6.51%     -3.07%         -2.23%     -6.47%
AppendFloat/64Fixed3               +5.27%       +3.06%        ~       +2.08%              ~       +6.20%     -2.85%         -3.07%     -6.21%
AppendFloat/64Fixed4               +7.82%       +3.70%   +2.25%       +2.01%         +5.18%       +5.68%     -2.18%         -1.31%     -3.55%
AppendFloat/64Fixed12              +3.81%       +3.67%        ~       +3.91%              ~       +5.71%     -9.49%        -12.13%    -11.63%
AppendFloat/64Fixed16              -6.26%       -1.42%   -3.37%       -3.15%         -2.03%       +1.15%    -16.18%        -21.43%    -20.40%
AppendFloat/64Fixed12Hard               ~       +2.34%   -1.44%            ~         -1.99%       +9.96%    -10.34%        -13.89%    -13.23%
AppendFloat/64Fixed17Hard          -3.86%       -0.96%   -3.23%       -2.85%         -5.54%       +9.12%    -15.76%        -19.37%    -18.01%
AppendFloat/64Fixed18Hard               ~            ~   -1.34%            ~              ~            ~          ~              ~          ~
AppendFloat/Slowpath64                  ~            ~        ~            ~              ~       -0.63%     +0.94%              ~          ~
AppendFloat/SlowpathDenormal64          ~            ~        ~       -0.96%              ~       -0.53%     +0.65%         +1.08%          ~
AppendUint                         -5.10%       +2.64%   -4.21%       -8.75%         -1.69%       -9.73%    -60.54%        -18.30%    -22.34%
AppendUintVarlen/digits=1          +2.91%       +4.79%   -7.80%            ~         +7.60%            ~     -4.13%              ~     +3.56%
AppendUintVarlen/digits=2               ~       -0.36%        ~            ~              ~       +0.99%     -5.45%              ~     +2.71%
AppendUintVarlen/digits=3          -3.69%       -9.19%   -5.28%      -11.24%        -12.90%      -28.62%    -42.12%        -43.20%    -32.72%
AppendUintVarlen/digits=4          -5.18%      -14.79%   -6.11%      -11.44%        -17.82%      -31.59%    -39.66%        -40.86%    -27.99%
AppendUintVarlen/digits=5               ~       -8.76%  -11.18%      -15.73%         -6.94%      -16.84%    -37.31%        -40.43%    -29.18%
AppendUintVarlen/digits=6          -1.48%       -8.18%  -11.67%      -15.29%         -5.74%      -16.51%    -38.73%        -39.42%    -26.00%
AppendUintVarlen/digits=7          -9.34%       -9.38%  -14.86%      -18.42%         -4.30%      -12.42%    -35.23%        -38.90%    -26.84%
AppendUintVarlen/digits=8         -10.37%       -8.50%  -17.32%      -17.57%         -6.52%      -21.17%    -35.56%        -37.64%    -22.88%
AppendUintVarlen/digits=9         -15.94%      -10.40%  -16.51%      -21.68%         -8.14%      -12.55%    -33.50%        -36.50%    -23.86%
AppendUintVarlen/digits=10         -4.16%       +7.58%   -6.11%       -7.51%         -5.73%       -7.21%    -40.04%        -26.20%    -25.59%
AppendUintVarlen/digits=11         -9.66%       -3.38%  -12.55%      -14.52%         -5.92%      -16.85%    -46.87%        -34.70%    -32.89%
AppendUintVarlen/digits=12         -7.75%       +3.13%   -5.16%      -11.19%         -5.28%       -9.87%    -52.39%        -33.95%    -33.40%
AppendUintVarlen/digits=13        -14.43%       -6.62%  -12.24%      -16.02%         -3.26%      -18.73%    -57.28%        -33.80%    -31.58%
AppendUintVarlen/digits=14         -8.62%       +0.74%   -7.87%      -13.63%         -3.57%      -10.55%    -62.94%        -34.30%    -35.06%
AppendUintVarlen/digits=15        -14.52%       -6.86%  -14.08%      -17.37%         -4.55%      -23.38%    -61.99%        -33.33%    -32.28%
AppendUintVarlen/digits=16        -10.77%       -2.06%   -7.70%      -15.64%         -4.43%      -13.30%    -64.95%        -33.08%    -32.25%
AppendUintVarlen/digits=17        -14.18%       -8.84%  -12.96%      -18.62%         -7.55%      -21.40%    -66.71%        -31.96%    -31.40%
AppendUintVarlen/digits=18        -11.04%       -3.66%   -8.43%      -16.19%         -5.77%      -11.42%    -71.09%        -31.44%    -32.31%
AppendUintVarlen/digits=19         -8.62%       +0.33%   -9.66%      -12.56%         -5.37%      -11.96%    -71.30%        -23.09%    -31.52%
AppendUintVarlen/digits=20         -9.26%       +0.36%   -6.55%      -12.95%         -6.83%      -13.41%    -74.49%        -31.80%    -38.76%

host: local
                                 │ 428dc15ab39 │             c6ec0aa13de             │
                                 │   sec/op    │   sec/op     vs base                │
AppendFloat/Decimal-4              40.13n ± 2%   40.15n ± 2%        ~ (p=0.773 n=40)
AppendFloat/Float-4                56.98n ± 1%   57.27n ± 1%        ~ (p=0.394 n=40)
AppendFloat/Exp-4                  61.46n ± 1%   61.52n ± 1%        ~ (p=0.829 n=40)
AppendFloat/NegExp-4               60.24n ± 1%   59.99n ± 2%        ~ (p=0.912 n=40)
AppendFloat/LongExp-4              62.09n ± 2%   62.37n ± 2%        ~ (p=0.394 n=40)
AppendFloat/Big-4                  67.41n ± 1%   66.99n ± 1%        ~ (p=0.292 n=40)
AppendFloat/BinaryExp-4            32.27n ± 2%   30.38n ± 2%   -5.86% (p=0.000 n=40)
AppendFloat/32Integer-4            39.68n ± 1%   39.34n ± 1%        ~ (p=0.233 n=40)
AppendFloat/32ExactFraction-4      57.95n ± 1%   57.88n ± 2%        ~ (p=0.900 n=40)
AppendFloat/32Point-4              56.40n ± 1%   56.58n ± 2%        ~ (p=0.196 n=40)
AppendFloat/32Exp-4                63.12n ± 2%   63.39n ± 1%        ~ (p=0.082 n=40)
AppendFloat/32NegExp-4             59.64n ± 1%   60.29n ± 1%        ~ (p=0.192 n=40)
AppendFloat/32Shortest-4           51.58n ± 1%   51.98n ± 0%        ~ (p=0.082 n=40)
AppendFloat/32Fixed8Hard-4         39.91n ± 1%   41.74n ± 1%   +4.58% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4         43.56n ± 1%   45.53n ± 1%   +4.52% (p=0.000 n=40)
AppendFloat/64Fixed1-4             34.61n ± 2%   35.77n ± 2%   +3.37% (p=0.000 n=40)
AppendFloat/64Fixed2-4             33.91n ± 1%   35.07n ± 1%   +3.44% (p=0.000 n=40)
AppendFloat/64Fixed3-4             35.36n ± 1%   37.23n ± 1%   +5.27% (p=0.000 n=40)
AppendFloat/64Fixed4-4             33.95n ± 1%   36.60n ± 1%   +7.82% (p=0.000 n=40)
AppendFloat/64Fixed12-4            57.03n ± 1%   59.20n ± 2%   +3.81% (p=0.000 n=40)
AppendFloat/64Fixed16-4            51.82n ± 1%   48.58n ± 0%   -6.26% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4        48.32n ± 1%   49.00n ± 0%        ~ (p=0.118 n=40)
AppendFloat/64Fixed17Hard-4        57.40n ± 2%   55.18n ± 5%   -3.86% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4        3.298µ ± 1%   3.291µ ± 1%        ~ (p=0.927 n=40)
AppendFloat/Slowpath64-4           61.94n ± 3%   62.08n ± 3%        ~ (p=0.324 n=40)
AppendFloat/SlowpathDenormal64-4   59.94n ± 1%   59.82n ± 1%        ~ (p=0.288 n=40)
AppendUint-4                       180.6n ± 2%   171.3n ± 2%   -5.10% (p=0.000 n=40)
AppendUintVarlen/digits=1-4        4.475n ± 0%   4.605n ± 0%   +2.91% (p=0.000 n=40)
AppendUintVarlen/digits=2-4        4.424n ± 1%   4.486n ± 1%        ~ (p=0.025 n=40)
AppendUintVarlen/digits=3-4        12.46n ± 4%   12.00n ± 4%   -3.69% (p=0.000 n=40)
AppendUintVarlen/digits=4-4        11.68n ± 2%   11.08n ± 2%   -5.18% (p=0.000 n=40)
AppendUintVarlen/digits=5-4        11.89n ± 0%   11.82n ± 0%        ~ (p=0.001 n=40)
AppendUintVarlen/digits=6-4        12.18n ± 0%   12.00n ± 0%   -1.48% (p=0.000 n=40)
AppendUintVarlen/digits=7-4        13.49n ± 2%   12.23n ± 2%   -9.34% (p=0.000 n=40)
AppendUintVarlen/digits=8-4        13.21n ± 1%   11.84n ± 2%  -10.37% (p=0.000 n=40)
AppendUintVarlen/digits=9-4        15.21n ± 2%   12.79n ± 2%  -15.94% (p=0.000 n=40)
AppendUintVarlen/digits=10-4       15.49n ± 3%   14.85n ± 2%   -4.16% (p=0.000 n=40)
AppendUintVarlen/digits=11-4       16.82n ± 1%   15.20n ± 1%   -9.66% (p=0.000 n=40)
AppendUintVarlen/digits=12-4       17.42n ± 2%   16.07n ± 3%   -7.75% (p=0.000 n=40)
AppendUintVarlen/digits=13-4       18.75n ± 2%   16.05n ± 2%  -14.43% (p=0.000 n=40)
AppendUintVarlen/digits=14-4       18.90n ± 1%   17.27n ± 2%   -8.62% (p=0.000 n=40)
AppendUintVarlen/digits=15-4       20.49n ± 2%   17.52n ± 1%  -14.52% (p=0.000 n=40)
AppendUintVarlen/digits=16-4       21.08n ± 1%   18.81n ± 1%  -10.77% (p=0.000 n=40)
AppendUintVarlen/digits=17-4       22.64n ± 1%   19.43n ± 1%  -14.18% (p=0.000 n=40)
AppendUintVarlen/digits=18-4       22.96n ± 2%   20.42n ± 3%  -11.04% (p=0.000 n=40)
AppendUintVarlen/digits=19-4       24.58n ± 0%   22.46n ± 0%   -8.62% (p=0.000 n=40)
AppendUintVarlen/digits=20-4       25.23n ± 2%   22.89n ± 0%   -9.26% (p=0.000 n=40)
geomean                            33.23n        32.17n        -3.18%

host: linux-arm64
                                 │  428dc15ab39  │              c6ec0aa13de              │
                                 │    sec/op     │    sec/op      vs base                │
AppendFloat/Decimal-4              61.13n ± 0% ¹   61.15n ± 0% ¹        ~ (p=0.006 n=40)
AppendFloat/Float-4                88.90n ± 0% ¹   88.88n ± 0% ¹        ~ (p=0.528 n=40)
AppendFloat/Exp-4                  92.87n ± 0% ¹   92.87n ± 0% ¹        ~ (p=0.795 n=40)
AppendFloat/NegExp-4               93.06n ± 0% ¹   93.10n ± 0% ¹        ~ (p=0.031 n=40)
AppendFloat/LongExp-4              100.3n ± 0% ¹   100.3n ± 0% ¹        ~ (p=0.184 n=40)
AppendFloat/Big-4                  105.5n ± 0% ¹   105.6n ± 0% ¹        ~ (p=0.007 n=40)
AppendFloat/BinaryExp-4            47.80n ± 0% ¹   46.75n ± 0% ¹   -2.20% (p=0.000 n=40)
AppendFloat/32Integer-4            61.24n ± 0% ¹   61.24n ± 0% ¹        ~ (p=0.809 n=40)
AppendFloat/32ExactFraction-4      85.63n ± 0% ¹   85.69n ± 0% ¹        ~ (p=0.002 n=40)
AppendFloat/32Point-4              83.23n ± 0% ¹   83.24n ± 0% ¹        ~ (p=0.410 n=40)
AppendFloat/32Exp-4                92.18n ± 0% ¹   92.19n ± 0% ¹        ~ (p=0.104 n=40)
AppendFloat/32NegExp-4             87.69n ± 0% ¹   87.70n ± 0% ¹        ~ (p=0.106 n=40)
AppendFloat/32Shortest-4           77.13n ± 0% ¹   77.12n ± 0% ¹        ~ (p=0.599 n=40)
AppendFloat/32Fixed8Hard-4         54.55n ± 0% ¹   55.61n ± 0% ¹   +1.94% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4         60.91n ± 0% ¹   64.21n ± 0% ¹   +5.41% (p=0.000 n=40)
AppendFloat/64Fixed1-4             51.37n ± 0% ¹   53.14n ± 0% ¹   +3.45% (p=0.000 n=40)
AppendFloat/64Fixed2-4             50.34n ± 0% ¹   52.08n ± 0% ¹   +3.46% (p=0.000 n=40)
AppendFloat/64Fixed3-4             50.91n ± 0% ¹   52.47n ± 0% ¹   +3.06% (p=0.000 n=40)
AppendFloat/64Fixed4-4             48.59n ± 0% ¹   50.39n ± 0% ¹   +3.70% (p=0.000 n=40)
AppendFloat/64Fixed12-4            81.00n ± 0% ¹   83.98n ± 0% ¹   +3.67% (p=0.000 n=40)
AppendFloat/64Fixed16-4            71.60n ± 0% ¹   70.59n ± 0% ¹   -1.42% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4        66.07n ± 0% ¹   67.62n ± 0% ¹   +2.34% (p=0.000 n=40)
AppendFloat/64Fixed17Hard-4        79.00n ± 0% ¹   78.24n ± 0% ¹   -0.96% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4        4.290µ ± 0% ¹   4.291µ ± 0% ¹        ~ (p=0.674 n=40)
AppendFloat/Slowpath64-4           97.87n ± 0% ¹   97.88n ± 0% ¹        ~ (p=0.847 n=40)
AppendFloat/SlowpathDenormal64-4   95.66n ± 0% ¹   95.66n ± 0% ¹        ~ (p=0.519 n=40)
AppendUint-4                       269.2n ± 0% ¹   276.3n ± 0% ¹   +2.64% (p=0.000 n=40)
AppendUintVarlen/digits=1-4        6.106n ± 0% ¹   6.398n ± 0% ¹   +4.79% (p=0.000 n=40)
AppendUintVarlen/digits=2-4        6.082n ± 0% ¹   6.060n ± 0% ¹   -0.36% (p=0.000 n=40)
AppendUintVarlen/digits=3-4        13.39n ± 0% ¹   12.16n ± 0% ¹   -9.19% (p=0.000 n=40)
AppendUintVarlen/digits=4-4        15.01n ± 0% ¹   12.79n ± 0% ¹  -14.79% (p=0.000 n=40)
AppendUintVarlen/digits=5-4        15.92n ± 0% ¹   14.52n ± 0% ¹   -8.76% (p=0.000 n=40)
AppendUintVarlen/digits=6-4        16.25n ± 0% ¹   14.92n ± 0% ¹   -8.18% (p=0.000 n=40)
AppendUintVarlen/digits=7-4        18.71n ± 0% ¹   16.96n ± 0% ¹   -9.38% (p=0.000 n=40)
AppendUintVarlen/digits=8-4        18.94n ± 0% ¹   17.33n ± 0% ¹   -8.50% (p=0.000 n=40)
AppendUintVarlen/digits=9-4        21.73n ± 0% ¹   19.47n ± 0% ¹  -10.40% (p=0.000 n=40)
AppendUintVarlen/digits=10-4       22.02n ± 0% ¹   23.69n ± 0% ¹   +7.58% (p=0.000 n=40)
AppendUintVarlen/digits=11-4       24.85n ± 0% ¹   24.01n ± 0% ¹   -3.38% (p=0.000 n=40)
AppendUintVarlen/digits=12-4       25.21n ± 0% ¹   26.00n ± 0% ¹   +3.13% (p=0.000 n=40)
AppendUintVarlen/digits=13-4       28.01n ± 0% ¹   26.15n ± 0% ¹   -6.62% (p=0.000 n=40)
AppendUintVarlen/digits=14-4       28.36n ± 0% ¹   28.57n ± 0% ¹   +0.74% (p=0.000 n=40)
AppendUintVarlen/digits=15-4       31.20n ± 0% ¹   29.06n ± 0% ¹   -6.86% (p=0.000 n=40)
AppendUintVarlen/digits=16-4       31.55n ± 0% ¹   30.90n ± 0% ¹   -2.06% (p=0.000 n=40)
AppendUintVarlen/digits=17-4       35.05n ± 0% ¹   31.95n ± 0% ¹   -8.84% (p=0.000 n=40)
AppendUintVarlen/digits=18-4       35.50n ± 0% ¹   34.20n ± 0% ¹   -3.66% (p=0.000 n=40)
AppendUintVarlen/digits=19-4       38.22n ± 0% ¹   38.34n ± 0% ¹   +0.33% (p=0.000 n=40)
AppendUintVarlen/digits=20-4       38.68n ± 0% ¹   38.82n ± 0% ¹   +0.36% (p=0.000 n=40)
geomean                            48.25n          47.59n          -1.36%
¹ benchmarks vary in cpu

host: s7
                                 │ 428dc15ab39  │             c6ec0aa13de             │
                                 │    sec/op    │   sec/op     vs base                │
AppendFloat/Decimal-4               23.81n ± 1%   23.76n ± 1%        ~ (p=0.885 n=40)
AppendFloat/Float-4                 36.85n ± 1%   36.97n ± 1%        ~ (p=0.002 n=40)
AppendFloat/Exp-4                   36.82n ± 1%   36.59n ± 1%        ~ (p=0.292 n=40)
AppendFloat/NegExp-4                37.44n ± 1%   37.41n ± 1%        ~ (p=0.596 n=40)
AppendFloat/LongExp-4               39.82n ± 1%   39.78n ± 1%        ~ (p=0.025 n=40)
AppendFloat/Big-4                   41.94n ± 1%   41.81n ± 1%        ~ (p=0.054 n=40)
AppendFloat/BinaryExp-4             20.18n ± 1%   19.52n ± 0%   -3.27% (p=0.000 n=40)
AppendFloat/32Integer-4             23.88n ± 0%   23.92n ± 0%        ~ (p=0.408 n=40)
AppendFloat/32ExactFraction-4       36.45n ± 1%   36.26n ± 0%        ~ (p=0.088 n=40)
AppendFloat/32Point-4               35.23n ± 1%   35.33n ± 1%        ~ (p=0.470 n=40)
AppendFloat/32Exp-4                 38.04n ± 1%   37.89n ± 1%        ~ (p=0.885 n=40)
AppendFloat/32NegExp-4              36.20n ± 0%   36.21n ± 1%        ~ (p=0.923 n=40)
AppendFloat/32Shortest-4            32.55n ± 0%   32.42n ± 1%        ~ (p=0.238 n=40)
AppendFloat/32Fixed8Hard-4          24.70n ± 0%   25.38n ± 1%   +2.77% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4          27.13n ± 0%   28.25n ± 1%   +4.13% (p=0.000 n=40)
AppendFloat/64Fixed1-4              21.40n ± 0%   21.68n ± 1%   +1.31% (p=0.000 n=40)
AppendFloat/64Fixed2-4              21.17n ± 0%   21.33n ± 1%   +0.80% (p=0.001 n=40)
AppendFloat/64Fixed3-4              22.09n ± 1%   22.29n ± 1%        ~ (p=0.003 n=40)
AppendFloat/64Fixed4-4              21.38n ± 1%   21.86n ± 1%   +2.25% (p=0.000 n=40)
AppendFloat/64Fixed12-4             35.17n ± 0%   35.28n ± 1%        ~ (p=0.125 n=40)
AppendFloat/64Fixed16-4             32.02n ± 1%   30.94n ± 1%   -3.37% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4         29.79n ± 1%   29.36n ± 0%   -1.44% (p=0.000 n=40)
AppendFloat/64Fixed17Hard-4         34.79n ± 1%   33.66n ± 0%   -3.23% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4         1.983µ ± 1%   1.956µ ± 1%   -1.34% (p=0.000 n=40)
AppendFloat/Slowpath64-4            38.15n ± 0%   37.84n ± 1%        ~ (p=0.039 n=40)
AppendFloat/SlowpathDenormal64-4    38.06n ± 1%   38.24n ± 1%        ~ (p=0.025 n=40)
AppendUint-4                        121.0n ± 0%   115.9n ± 1%   -4.21% (p=0.000 n=40)
AppendUintVarlen/digits=1-4         2.557n ± 1%   2.358n ± 4%   -7.80% (p=0.000 n=40)
AppendUintVarlen/digits=2-4         2.387n ± 4%   2.405n ± 4%        ~ (p=0.149 n=40)
AppendUintVarlen/digits=3-4         6.198n ± 1%   5.871n ± 1%   -5.28% (p=0.000 n=40)
AppendUintVarlen/digits=4-4         6.196n ± 0%   5.817n ± 1%   -6.11% (p=0.000 n=40)
AppendUintVarlen/digits=5-4         6.773n ± 1%   6.016n ± 1%  -11.18% (p=0.000 n=40)
AppendUintVarlen/digits=6-4         6.948n ± 1%   6.136n ± 1%  -11.67% (p=0.000 n=40)
AppendUintVarlen/digits=7-4         8.157n ± 1%   6.944n ± 1%  -14.86% (p=0.000 n=40)
AppendUintVarlen/digits=8-4         8.364n ± 1%   6.915n ± 0%  -17.32% (p=0.000 n=40)
AppendUintVarlen/digits=9-4         9.740n ± 1%   8.132n ± 1%  -16.51% (p=0.000 n=40)
AppendUintVarlen/digits=10-4        9.836n ± 1%   9.235n ± 1%   -6.11% (p=0.000 n=40)
AppendUintVarlen/digits=11-4       11.000n ± 1%   9.620n ± 0%  -12.55% (p=0.000 n=40)
AppendUintVarlen/digits=12-4        11.14n ± 1%   10.57n ± 1%   -5.16% (p=0.000 n=40)
AppendUintVarlen/digits=13-4        12.30n ± 1%   10.79n ± 1%  -12.24% (p=0.000 n=40)
AppendUintVarlen/digits=14-4        12.44n ± 1%   11.46n ± 0%   -7.87% (p=0.000 n=40)
AppendUintVarlen/digits=15-4        13.71n ± 1%   11.78n ± 1%  -14.08% (p=0.000 n=40)
AppendUintVarlen/digits=16-4        13.82n ± 1%   12.76n ± 1%   -7.70% (p=0.000 n=40)
AppendUintVarlen/digits=17-4        14.97n ± 1%   13.03n ± 0%  -12.96% (p=0.000 n=40)
AppendUintVarlen/digits=18-4        15.36n ± 1%   14.06n ± 1%   -8.43% (p=0.000 n=40)
AppendUintVarlen/digits=19-4        16.40n ± 1%   14.81n ± 1%   -9.66% (p=0.000 n=40)
AppendUintVarlen/digits=20-4        16.48n ± 0%   15.40n ± 1%   -6.55% (p=0.000 n=40)
geomean                             20.56n        19.65n        -4.42%

host: linux-amd64
                                 │ 428dc15ab39 │             c6ec0aa13de             │
                                 │   sec/op    │   sec/op     vs base                │
AppendFloat/Decimal-4              64.49n ± 0%   64.79n ± 2%        ~ (p=0.169 n=40)
AppendFloat/Float-4                95.98n ± 4%   98.54n ± 4%   +2.67% (p=0.000 n=40)
AppendFloat/Exp-4                  97.10n ± 1%   97.99n ± 4%        ~ (p=0.002 n=40)
AppendFloat/NegExp-4               98.10n ± 0%   99.87n ± 4%   +1.80% (p=0.000 n=40)
AppendFloat/LongExp-4              106.7n ± 4%   105.3n ± 4%   -1.36% (p=0.001 n=40)
AppendFloat/Big-4                  116.8n ± 3%   112.3n ± 4%   -3.94% (p=0.001 n=40)
AppendFloat/BinaryExp-4            57.70n ± 3%   47.79n ± 3%  -17.16% (p=0.000 n=40)
AppendFloat/32Integer-4            64.75n ± 3%   64.71n ± 3%        ~ (p=0.700 n=40)
AppendFloat/32ExactFraction-4      91.48n ± 2%   94.19n ± 3%   +2.96% (p=0.000 n=40)
AppendFloat/32Point-4              92.48n ± 2%   92.73n ± 4%        ~ (p=0.389 n=40)
AppendFloat/32Exp-4                103.6n ± 2%   103.4n ± 1%        ~ (p=0.069 n=40)
AppendFloat/32NegExp-4             95.16n ± 1%   94.33n ± 0%   -0.86% (p=0.001 n=40)
AppendFloat/32Shortest-4           85.43n ± 4%   84.89n ± 1%        ~ (p=0.082 n=40)
AppendFloat/32Fixed8Hard-4         64.42n ± 3%   61.59n ± 0%   -4.39% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4         69.74n ± 3%   71.91n ± 4%   +3.10% (p=0.000 n=40)
AppendFloat/64Fixed1-4             59.70n ± 3%   59.16n ± 4%        ~ (p=0.051 n=40)
AppendFloat/64Fixed2-4             58.73n ± 2%   58.03n ± 0%        ~ (p=0.110 n=40)
AppendFloat/64Fixed3-4             57.92n ± 4%   59.13n ± 4%   +2.08% (p=0.000 n=40)
AppendFloat/64Fixed4-4             55.21n ± 3%   56.33n ± 4%   +2.01% (p=0.000 n=40)
AppendFloat/64Fixed12-4            87.98n ± 3%   91.42n ± 1%   +3.91% (p=0.000 n=40)
AppendFloat/64Fixed16-4            80.05n ± 3%   77.52n ± 4%   -3.15% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4        75.03n ± 4%   74.99n ± 0%        ~ (p=0.641 n=40)
AppendFloat/64Fixed17Hard-4        87.45n ± 1%   84.96n ± 2%   -2.85% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4        4.903µ ± 3%   4.912µ ± 3%        ~ (p=0.829 n=40)
AppendFloat/Slowpath64-4           101.8n ± 1%   101.4n ± 4%        ~ (p=0.268 n=40)
AppendFloat/SlowpathDenormal64-4   101.0n ± 4%   100.1n ± 3%   -0.96% (p=0.000 n=40)
AppendUint-4                       336.7n ± 1%   307.2n ± 0%   -8.75% (p=0.000 n=40)
AppendUintVarlen/digits=1-4        6.069n ± 1%   6.069n ± 1%        ~ (p=0.904 n=40)
AppendUintVarlen/digits=2-4        5.920n ± 3%   5.925n ± 3%        ~ (p=0.010 n=40)
AppendUintVarlen/digits=3-4        16.33n ± 1%   14.49n ± 2%  -11.24% (p=0.000 n=40)
AppendUintVarlen/digits=4-4        16.70n ± 2%   14.79n ± 2%  -11.44% (p=0.000 n=40)
AppendUintVarlen/digits=5-4        19.33n ± 1%   16.29n ± 1%  -15.73% (p=0.000 n=40)
AppendUintVarlen/digits=6-4        20.15n ± 2%   17.07n ± 1%  -15.29% (p=0.000 n=40)
AppendUintVarlen/digits=7-4        22.78n ± 2%   18.58n ± 1%  -18.42% (p=0.000 n=40)
AppendUintVarlen/digits=8-4        23.56n ± 3%   19.43n ± 2%  -17.57% (p=0.000 n=40)
AppendUintVarlen/digits=9-4        27.12n ± 3%   21.24n ± 3%  -21.68% (p=0.000 n=40)
AppendUintVarlen/digits=10-4       27.10n ± 2%   25.07n ± 3%   -7.51% (p=0.000 n=40)
AppendUintVarlen/digits=11-4       29.72n ± 3%   25.41n ± 3%  -14.52% (p=0.000 n=40)
AppendUintVarlen/digits=12-4       30.35n ± 3%   26.95n ± 4%  -11.19% (p=0.000 n=40)
AppendUintVarlen/digits=13-4       32.98n ± 0%   27.70n ± 3%  -16.02% (p=0.000 n=40)
AppendUintVarlen/digits=14-4       33.89n ± 2%   29.28n ± 3%  -13.63% (p=0.000 n=40)
AppendUintVarlen/digits=15-4       36.45n ± 3%   30.11n ± 1%  -17.37% (p=0.000 n=40)
AppendUintVarlen/digits=16-4       37.12n ± 0%   31.31n ± 1%  -15.64% (p=0.000 n=40)
AppendUintVarlen/digits=17-4       39.84n ± 1%   32.42n ± 0%  -18.62% (p=0.000 n=40)
AppendUintVarlen/digits=18-4       40.53n ± 0%   33.97n ± 3%  -16.19% (p=0.000 n=40)
AppendUintVarlen/digits=19-4       43.20n ± 4%   37.78n ± 0%  -12.56% (p=0.000 n=40)
AppendUintVarlen/digits=20-4       43.87n ± 1%   38.19n ± 0%  -12.95% (p=0.000 n=40)
geomean                            54.70n        51.10n        -6.58%

host: linux-ppc64le
                                 │ 428dc15ab39  │             c6ec0aa13de             │
                                 │    sec/op    │   sec/op     vs base                │
AppendFloat/Decimal-4               55.69n ± 3%   56.06n ± 3%        ~ (p=0.821 n=40)
AppendFloat/Float-4                 79.23n ± 1%   77.13n ± 3%        ~ (p=0.019 n=40)
AppendFloat/Exp-4                   91.14n ± 2%   86.58n ± 2%   -5.01% (p=0.000 n=40)
AppendFloat/NegExp-4                90.77n ± 1%   85.43n ± 6%        ~ (p=0.003 n=40)
AppendFloat/LongExp-4               93.40n ± 2%   91.21n ± 2%   -2.34% (p=0.000 n=40)
AppendFloat/Big-4                  101.55n ± 3%   98.84n ± 2%   -2.66% (p=0.000 n=40)
AppendFloat/BinaryExp-4             45.16n ± 3%   42.05n ± 2%   -6.89% (p=0.000 n=40)
AppendFloat/32Integer-4             56.50n ± 3%   57.45n ± 2%        ~ (p=0.821 n=40)
AppendFloat/32ExactFraction-4       80.94n ± 2%   80.60n ± 1%        ~ (p=0.106 n=40)
AppendFloat/32Point-4               77.03n ± 3%   76.69n ± 2%        ~ (p=0.242 n=40)
AppendFloat/32Exp-4                 92.44n ± 1%   88.70n ± 1%   -4.05% (p=0.000 n=40)
AppendFloat/32NegExp-4              89.50n ± 2%   85.06n ± 2%   -4.97% (p=0.000 n=40)
AppendFloat/32Shortest-4            74.63n ± 2%   72.75n ± 4%        ~ (p=0.042 n=40)
AppendFloat/32Fixed8Hard-4          58.18n ± 2%   56.86n ± 1%        ~ (p=0.002 n=40)
AppendFloat/32Fixed9Hard-4          64.17n ± 1%   61.06n ± 1%   -4.84% (p=0.000 n=40)
AppendFloat/64Fixed1-4              47.56n ± 2%   50.86n ± 1%   +6.93% (p=0.000 n=40)
AppendFloat/64Fixed2-4              47.87n ± 4%   50.75n ± 2%   +6.03% (p=0.000 n=40)
AppendFloat/64Fixed3-4              50.84n ± 2%   51.68n ± 1%        ~ (p=0.014 n=40)
AppendFloat/64Fixed4-4              46.29n ± 3%   48.69n ± 4%   +5.18% (p=0.000 n=40)
AppendFloat/64Fixed12-4             79.97n ± 1%   85.03n ± 4%        ~ (p=0.001 n=40)
AppendFloat/64Fixed16-4             73.18n ± 1%   71.70n ± 2%   -2.03% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4         68.41n ± 4%   67.06n ± 1%   -1.99% (p=0.000 n=40)
AppendFloat/64Fixed17Hard-4         81.02n ± 1%   76.54n ± 1%   -5.54% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4         5.184µ ± 0%   5.215µ ± 1%        ~ (p=0.056 n=40)
AppendFloat/Slowpath64-4            89.16n ± 2%   88.85n ± 2%        ~ (p=0.405 n=40)
AppendFloat/SlowpathDenormal64-4    84.27n ± 3%   84.38n ± 1%        ~ (p=0.424 n=40)
AppendUint-4                        277.5n ± 1%   272.9n ± 1%   -1.69% (p=0.000 n=40)
AppendUintVarlen/digits=1-4         5.044n ± 3%   5.428n ± 1%   +7.60% (p=0.000 n=40)
AppendUintVarlen/digits=2-4         5.051n ± 1%   5.038n ± 2%        ~ (p=0.613 n=40)
AppendUintVarlen/digits=3-4         12.13n ± 4%   10.57n ± 2%  -12.90% (p=0.000 n=40)
AppendUintVarlen/digits=4-4         13.33n ± 3%   10.95n ± 1%  -17.82% (p=0.000 n=40)
AppendUintVarlen/digits=5-4         14.05n ± 2%   13.08n ± 3%   -6.94% (p=0.000 n=40)
AppendUintVarlen/digits=6-4         14.46n ± 2%   13.63n ± 2%   -5.74% (p=0.000 n=40)
AppendUintVarlen/digits=7-4         17.11n ± 4%   16.38n ± 1%   -4.30% (p=0.000 n=40)
AppendUintVarlen/digits=8-4         17.34n ± 5%   16.20n ± 1%   -6.52% (p=0.000 n=40)
AppendUintVarlen/digits=9-4         21.06n ± 2%   19.34n ± 2%   -8.14% (p=0.000 n=40)
AppendUintVarlen/digits=10-4        21.11n ± 2%   19.90n ± 1%   -5.73% (p=0.000 n=40)
AppendUintVarlen/digits=11-4        24.25n ± 4%   22.81n ± 1%   -5.92% (p=0.000 n=40)
AppendUintVarlen/digits=12-4        24.53n ± 3%   23.23n ± 2%   -5.28% (p=0.000 n=40)
AppendUintVarlen/digits=13-4        27.14n ± 5%   26.26n ± 1%   -3.26% (p=0.000 n=40)
AppendUintVarlen/digits=14-4        27.72n ± 6%   26.73n ± 0%   -3.57% (p=0.000 n=40)
AppendUintVarlen/digits=15-4        31.23n ± 3%   29.80n ± 1%   -4.55% (p=0.000 n=40)
AppendUintVarlen/digits=16-4        30.78n ± 3%   29.41n ± 1%   -4.43% (p=0.000 n=40)
AppendUintVarlen/digits=17-4        35.04n ± 1%   32.39n ± 0%   -7.55% (p=0.000 n=40)
AppendUintVarlen/digits=18-4        35.10n ± 7%   33.08n ± 0%   -5.77% (p=0.000 n=40)
AppendUintVarlen/digits=19-4        38.26n ± 6%   36.21n ± 0%   -5.37% (p=0.000 n=40)
AppendUintVarlen/digits=20-4        39.24n ± 3%   36.56n ± 0%   -6.83% (p=0.000 n=40)
geomean                             46.39n        44.95n        -3.11%

host: linux-s390x
                                 │  428dc15ab39  │              c6ec0aa13de               │
                                 │    sec/op     │     sec/op      vs base                │
AppendFloat/Decimal-4              70.92n ± 0% ¹    70.81n ± 1% ¹        ~ (p=0.668 n=40)
AppendFloat/Float-4                111.5n ± 0% ¹    111.8n ± 0% ¹        ~ (p=0.143 n=40)
AppendFloat/Exp-4                  119.1n ± 1% ¹    118.1n ± 1% ¹   -0.88% (p=0.000 n=40)
AppendFloat/NegExp-4               119.7n ± 0% ¹    117.8n ± 0% ¹   -1.55% (p=0.000 n=40)
AppendFloat/LongExp-4              128.1n ± 0% ¹    127.8n ± 1% ¹        ~ (p=0.181 n=40)
AppendFloat/Big-4                  131.3n ± 1% ¹    130.5n ± 1% ¹   -0.61% (p=0.001 n=40)
AppendFloat/BinaryExp-4            58.47n ± 0% ¹    58.29n ± 0% ¹        ~ (p=0.189 n=40)
AppendFloat/32Integer-4            72.66n ± 0% ¹    72.31n ± 1% ¹        ~ (p=0.012 n=40)
AppendFloat/32ExactFraction-4      108.6n ± 0% ¹    108.5n ± 1% ¹        ~ (p=0.754 n=40)
AppendFloat/32Point-4              108.6n ± 1% ¹    108.2n ± 0% ¹        ~ (p=0.073 n=40)
AppendFloat/32Exp-4                116.9n ± 1% ¹    117.8n ± 0% ¹        ~ (p=0.008 n=40)
AppendFloat/32NegExp-4             117.9n ± 0% ¹    118.0n ± 0% ¹        ~ (p=0.954 n=40)
AppendFloat/32Shortest-4           107.7n ± 1% ¹    107.0n ± 1% ¹        ~ (p=0.106 n=40)
AppendFloat/32Fixed8Hard-4         71.77n ± 1% ¹    74.92n ± 1% ¹   +4.39% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4         73.49n ± 0% ¹    84.03n ± 0% ¹  +14.34% (p=0.000 n=40)
AppendFloat/64Fixed1-4             63.55n ± 1% ¹    66.59n ± 1% ¹   +4.79% (p=0.000 n=40)
AppendFloat/64Fixed2-4             61.74n ± 1% ¹    65.77n ± 1% ¹   +6.51% (p=0.000 n=40)
AppendFloat/64Fixed3-4             63.84n ± 2% ¹    67.80n ± 1% ¹   +6.20% (p=0.000 n=40)
AppendFloat/64Fixed4-4             60.41n ± 1% ¹    63.84n ± 1% ¹   +5.68% (p=0.000 n=40)
AppendFloat/64Fixed12-4            98.06n ± 0% ¹   103.65n ± 0% ¹   +5.71% (p=0.000 n=40)
AppendFloat/64Fixed16-4            86.71n ± 0% ¹    87.70n ± 0% ¹   +1.15% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4        80.62n ± 1% ¹    88.65n ± 1% ¹   +9.96% (p=0.000 n=40)
AppendFloat/64Fixed17Hard-4        89.77n ± 1% ¹    97.96n ± 1% ¹   +9.12% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4        4.791µ ± 0% ¹    4.790µ ± 0% ¹        ~ (p=0.973 n=40)
AppendFloat/Slowpath64-4           126.0n ± 0% ¹    125.2n ± 0% ¹   -0.63% (p=0.000 n=40)
AppendFloat/SlowpathDenormal64-4   121.7n ± 0% ¹    121.1n ± 0% ¹   -0.53% (p=0.001 n=40)
AppendUint-4                       374.6n ± 1% ¹    338.2n ± 0% ¹   -9.73% (p=0.000 n=40)
AppendUintVarlen/digits=1-4        5.433n ± 0% ¹    5.416n ± 0% ¹        ~ (p=0.032 n=40)
AppendUintVarlen/digits=2-4        5.357n ± 0% ¹    5.410n ± 0% ¹   +0.99% (p=0.000 n=40)
AppendUintVarlen/digits=3-4        17.45n ± 0% ¹    12.46n ± 0% ¹  -28.62% (p=0.000 n=40)
AppendUintVarlen/digits=4-4        17.38n ± 0% ¹    11.89n ± 0% ¹  -31.59% (p=0.000 n=40)
AppendUintVarlen/digits=5-4        21.38n ± 0% ¹    17.78n ± 1% ¹  -16.84% (p=0.000 n=40)
AppendUintVarlen/digits=6-4        21.60n ± 0% ¹    18.03n ± 1% ¹  -16.51% (p=0.000 n=40)
AppendUintVarlen/digits=7-4        26.44n ± 0% ¹    23.15n ± 0% ¹  -12.42% (p=0.000 n=40)
AppendUintVarlen/digits=8-4        26.60n ± 0% ¹    20.97n ± 1% ¹  -21.17% (p=0.000 n=40)
AppendUintVarlen/digits=9-4        31.44n ± 0% ¹    27.49n ± 0% ¹  -12.55% (p=0.000 n=40)
AppendUintVarlen/digits=10-4       31.26n ± 1% ¹    29.00n ± 0% ¹   -7.21% (p=0.000 n=40)
AppendUintVarlen/digits=11-4       35.90n ± 0% ¹    29.84n ± 0% ¹  -16.85% (p=0.000 n=40)
AppendUintVarlen/digits=12-4       35.95n ± 0% ¹    32.40n ± 0% ¹   -9.87% (p=0.000 n=40)
AppendUintVarlen/digits=13-4       40.98n ± 0% ¹    33.31n ± 0% ¹  -18.73% (p=0.000 n=40)
AppendUintVarlen/digits=14-4       38.96n ± 0% ¹    34.85n ± 0% ¹  -10.55% (p=0.000 n=40)
AppendUintVarlen/digits=15-4       45.51n ± 0% ¹    34.87n ± 0% ¹  -23.38% (p=0.000 n=40)
AppendUintVarlen/digits=16-4       45.05n ± 0% ¹    39.05n ± 0% ¹  -13.30% (p=0.000 n=40)
AppendUintVarlen/digits=17-4       50.76n ± 0% ¹    39.89n ± 0% ¹  -21.40% (p=0.000 n=40)
AppendUintVarlen/digits=18-4       49.86n ± 1% ¹    44.16n ± 0% ¹  -11.42% (p=0.000 n=40)
AppendUintVarlen/digits=19-4       54.68n ± 0% ¹    48.14n ± 0% ¹  -11.96% (p=0.000 n=40)
AppendUintVarlen/digits=20-4       55.48n ± 0% ¹    48.04n ± 0% ¹  -13.41% (p=0.000 n=40)
geomean                            62.00n           58.40n          -5.80%
¹ benchmarks vary in cpu

host: linux-arm
                                 │ 428dc15ab39  │             c6ec0aa13de             │
                                 │    sec/op    │   sec/op     vs base                │
AppendFloat/Decimal-4               121.6n ± 0%   122.8n ± 0%   +0.99% (p=0.000 n=40)
AppendFloat/Float-4                 209.1n ± 0%   208.8n ± 0%   -0.17% (p=0.000 n=40)
AppendFloat/Exp-4                   208.8n ± 0%   208.5n ± 0%   -0.14% (p=0.000 n=40)
AppendFloat/NegExp-4                210.1n ± 0%   208.7n ± 0%   -0.67% (p=0.000 n=40)
AppendFloat/LongExp-4               217.5n ± 0%   218.4n ± 0%   +0.41% (p=0.000 n=40)
AppendFloat/Big-4                   237.8n ± 0%   240.2n ± 0%   +1.01% (p=0.000 n=40)
AppendFloat/BinaryExp-4            226.90n ± 0%   86.66n ± 0%  -61.81% (p=0.000 n=40)
AppendFloat/32Integer-4             121.9n ± 0%   122.8n ± 0%   +0.74% (p=0.000 n=40)
AppendFloat/32ExactFraction-4       174.0n ± 0%   174.1n ± 0%   +0.09% (p=0.000 n=40)
AppendFloat/32Point-4               171.9n ± 0%   174.2n ± 0%   +1.31% (p=0.000 n=40)
AppendFloat/32Exp-4                 195.4n ± 0%   195.3n ± 0%   -0.05% (p=0.000 n=40)
AppendFloat/32NegExp-4              174.0n ± 0%   174.4n ± 0%   +0.23% (p=0.000 n=40)
AppendFloat/32Shortest-4            167.5n ± 0%   168.7n ± 0%   +0.72% (p=0.000 n=40)
AppendFloat/32Fixed8Hard-4          115.4n ± 0%   104.6n ± 0%   -9.36% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4          144.9n ± 0%   139.3n ± 0%   -3.83% (p=0.000 n=40)
AppendFloat/64Fixed1-4              127.3n ± 0%   123.5n ± 0%   -2.99% (p=0.000 n=40)
AppendFloat/64Fixed2-4              123.6n ± 0%   119.8n ± 0%   -3.07% (p=0.000 n=40)
AppendFloat/64Fixed3-4              122.8n ± 0%   119.3n ± 0%   -2.85% (p=0.000 n=40)
AppendFloat/64Fixed4-4              114.5n ± 0%   112.0n ± 0%   -2.18% (p=0.000 n=40)
AppendFloat/64Fixed12-4             161.3n ± 0%   146.0n ± 0%   -9.49% (p=0.000 n=40)
AppendFloat/64Fixed16-4             168.7n ± 0%   141.4n ± 0%  -16.18% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4         152.3n ± 0%   136.6n ± 0%  -10.34% (p=0.000 n=40)
AppendFloat/64Fixed17Hard-4         182.7n ± 0%   153.9n ± 0%  -15.76% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4         7.976µ ± 0%   7.977µ ± 0%        ~ (p=0.093 n=40)
AppendFloat/Slowpath64-4            213.4n ± 0%   215.4n ± 0%   +0.94% (p=0.000 n=40)
AppendFloat/SlowpathDenormal64-4    214.0n ± 0%   215.4n ± 0%   +0.65% (p=0.000 n=40)
AppendUint-4                       1526.0n ± 0%   602.1n ± 0%  -60.54% (p=0.000 n=40)
AppendUintVarlen/digits=1-4         9.338n ± 0%   8.953n ± 0%   -4.13% (p=0.000 n=40)
AppendUintVarlen/digits=2-4         9.789n ± 0%   9.256n ± 0%   -5.45% (p=0.000 n=40)
AppendUintVarlen/digits=3-4         46.42n ± 0%   26.87n ± 0%  -42.12% (p=0.000 n=40)
AppendUintVarlen/digits=4-4         49.23n ± 0%   29.70n ± 0%  -39.66% (p=0.000 n=40)
AppendUintVarlen/digits=5-4         51.45n ± 0%   32.25n ± 0%  -37.31% (p=0.000 n=40)
AppendUintVarlen/digits=6-4         51.02n ± 0%   31.26n ± 0%  -38.73% (p=0.000 n=40)
AppendUintVarlen/digits=7-4         55.45n ± 0%   35.91n ± 0%  -35.23% (p=0.000 n=40)
AppendUintVarlen/digits=8-4         57.11n ± 0%   36.80n ± 0%  -35.56% (p=0.000 n=40)
AppendUintVarlen/digits=9-4         59.28n ± 0%   39.42n ± 0%  -33.50% (p=0.000 n=40)
AppendUintVarlen/digits=10-4        71.62n ± 0%   42.94n ± 0%  -40.04% (p=0.000 n=40)
AppendUintVarlen/digits=11-4        91.41n ± 0%   48.57n ± 0%  -46.87% (p=0.000 n=40)
AppendUintVarlen/digits=12-4       106.50n ± 0%   50.70n ± 0%  -52.39% (p=0.000 n=40)
AppendUintVarlen/digits=13-4       121.90n ± 0%   52.07n ± 0%  -57.28% (p=0.000 n=40)
AppendUintVarlen/digits=14-4       129.70n ± 0%   48.07n ± 0%  -62.94% (p=0.000 n=40)
AppendUintVarlen/digits=15-4       148.50n ± 0%   56.45n ± 0%  -61.99% (p=0.000 n=40)
AppendUintVarlen/digits=16-4       167.40n ± 0%   58.67n ± 0%  -64.95% (p=0.000 n=40)
AppendUintVarlen/digits=17-4       179.70n ± 0%   59.83n ± 0%  -66.71% (p=0.000 n=40)
AppendUintVarlen/digits=18-4       186.00n ± 0%   53.78n ± 0%  -71.09% (p=0.000 n=40)
AppendUintVarlen/digits=19-4       216.50n ± 0%   62.13n ± 0%  -71.30% (p=0.000 n=40)
AppendUintVarlen/digits=20-4       246.80n ± 0%   62.96n ± 0%  -74.49% (p=0.000 n=40)
geomean                             136.3n        95.52n       -29.95%

host: s7:GOARCH=386
                                 │ 428dc15ab39  │             c6ec0aa13de              │
                                 │    sec/op    │    sec/op     vs base                │
AppendFloat/Decimal-4               51.07n ± 1%    51.05n ± 0%        ~ (p=0.346 n=40)
AppendFloat/Float-4                 94.44n ± 1%    95.05n ± 0%        ~ (p=0.343 n=40)
AppendFloat/Exp-4                   97.89n ± 0%    98.59n ± 0%        ~ (p=0.271 n=40)
AppendFloat/NegExp-4                98.22n ± 1%    99.27n ± 0%        ~ (p=0.283 n=40)
AppendFloat/LongExp-4               100.3n ± 0%    101.4n ± 0%        ~ (p=0.001 n=40)
AppendFloat/Big-4                   109.1n ± 0%    110.0n ± 1%        ~ (p=0.141 n=40)
AppendFloat/BinaryExp-4             53.98n ± 1%    35.74n ± 1%  -33.80% (p=0.000 n=40)
AppendFloat/32Integer-4             49.90n ± 0%    50.41n ± 0%        ~ (p=0.005 n=40)
AppendFloat/32ExactFraction-4       78.22n ± 0%    79.49n ± 0%   +1.62% (p=0.000 n=40)
AppendFloat/32Point-4               75.75n ± 1%    75.90n ± 0%        ~ (p=0.119 n=40)
AppendFloat/32Exp-4                 89.74n ± 1%    90.58n ± 0%        ~ (p=0.088 n=40)
AppendFloat/32NegExp-4              79.34n ± 1%    80.22n ± 0%        ~ (p=0.005 n=40)
AppendFloat/32Shortest-4            74.46n ± 1%    74.43n ± 1%        ~ (p=1.000 n=40)
AppendFloat/32Fixed8Hard-4          47.28n ± 1%    41.62n ± 0%  -11.97% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4          64.92n ± 1%    63.72n ± 1%   -1.84% (p=0.000 n=40)
AppendFloat/64Fixed1-4              58.40n ± 1%    57.19n ± 1%   -2.07% (p=0.000 n=40)
AppendFloat/64Fixed2-4              55.79n ± 1%    54.55n ± 1%   -2.23% (p=0.000 n=40)
AppendFloat/64Fixed3-4              56.70n ± 1%    54.95n ± 0%   -3.07% (p=0.000 n=40)
AppendFloat/64Fixed4-4              51.85n ± 1%    51.18n ± 0%   -1.31% (p=0.000 n=40)
AppendFloat/64Fixed12-4             74.00n ± 0%    65.02n ± 0%  -12.13% (p=0.000 n=40)
AppendFloat/64Fixed16-4             80.23n ± 1%    63.04n ± 0%  -21.43% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4         70.64n ± 1%    60.83n ± 1%  -13.89% (p=0.000 n=40)
AppendFloat/64Fixed17Hard-4         86.02n ± 1%    69.36n ± 0%  -19.37% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4         3.736µ ± 1%    3.795µ ± 0%        ~ (p=0.010 n=40)
AppendFloat/Slowpath64-4            99.18n ± 1%   100.25n ± 0%        ~ (p=0.003 n=40)
AppendFloat/SlowpathDenormal64-4    97.35n ± 1%    98.41n ± 0%   +1.08% (p=0.001 n=40)
AppendUint-4                        356.3n ± 1%    291.2n ± 0%  -18.30% (p=0.000 n=40)
AppendUintVarlen/digits=1-4         3.923n ± 0%    3.919n ± 1%        ~ (p=0.061 n=40)
AppendUintVarlen/digits=2-4         3.917n ± 1%    3.924n ± 0%        ~ (p=0.048 n=40)
AppendUintVarlen/digits=3-4        17.205n ± 0%    9.772n ± 0%  -43.20% (p=0.000 n=40)
AppendUintVarlen/digits=4-4         17.18n ± 0%    10.16n ± 1%  -40.86% (p=0.000 n=40)
AppendUintVarlen/digits=5-4         18.33n ± 1%    10.92n ± 0%  -40.43% (p=0.000 n=40)
AppendUintVarlen/digits=6-4         18.67n ± 1%    11.31n ± 0%  -39.42% (p=0.000 n=40)
AppendUintVarlen/digits=7-4         19.77n ± 1%    12.08n ± 0%  -38.90% (p=0.000 n=40)
AppendUintVarlen/digits=8-4         19.95n ± 1%    12.44n ± 1%  -37.64% (p=0.000 n=40)
AppendUintVarlen/digits=9-4         21.44n ± 1%    13.61n ± 1%  -36.50% (p=0.000 n=40)
AppendUintVarlen/digits=10-4        24.31n ± 0%    17.94n ± 0%  -26.20% (p=0.000 n=40)
AppendUintVarlen/digits=11-4        27.75n ± 1%    18.12n ± 0%  -34.70% (p=0.000 n=40)
AppendUintVarlen/digits=12-4        28.76n ± 1%    18.99n ± 0%  -33.95% (p=0.000 n=40)
AppendUintVarlen/digits=13-4        29.12n ± 1%    19.28n ± 0%  -33.80% (p=0.000 n=40)
AppendUintVarlen/digits=14-4        30.56n ± 0%    20.07n ± 1%  -34.30% (p=0.000 n=40)
AppendUintVarlen/digits=15-4        30.71n ± 1%    20.48n ± 0%  -33.33% (p=0.000 n=40)
AppendUintVarlen/digits=16-4        31.86n ± 0%    21.32n ± 0%  -33.08% (p=0.000 n=40)
AppendUintVarlen/digits=17-4        31.51n ± 1%    21.43n ± 1%  -31.96% (p=0.000 n=40)
AppendUintVarlen/digits=18-4        32.46n ± 0%    22.26n ± 1%  -31.44% (p=0.000 n=40)
AppendUintVarlen/digits=19-4        35.42n ± 1%    27.25n ± 1%  -23.09% (p=0.000 n=40)
AppendUintVarlen/digits=20-4        39.50n ± 2%    26.94n ± 1%  -31.80% (p=0.000 n=40)
geomean                             48.59n         39.98n       -17.73%

host: linux-386
                                 │ 428dc15ab39  │             c6ec0aa13de             │
                                 │    sec/op    │   sec/op     vs base                │
AppendFloat/Decimal-4               148.4n ± 2%   147.8n ± 1%        ~ (p=0.053 n=40)
AppendFloat/Float-4                 284.1n ± 2%   281.9n ± 1%        ~ (p=0.001 n=40)
AppendFloat/Exp-4                   294.5n ± 3%   292.7n ± 1%        ~ (p=0.035 n=40)
AppendFloat/NegExp-4                295.4n ± 1%   295.9n ± 3%        ~ (p=0.799 n=40)
AppendFloat/LongExp-4               305.8n ± 2%   304.9n ± 2%        ~ (p=0.186 n=40)
AppendFloat/Big-4                   340.1n ± 3%   340.8n ± 4%        ~ (p=0.069 n=40)
AppendFloat/BinaryExp-4             139.1n ± 0%   100.7n ± 1%  -27.61% (p=0.000 n=40)
AppendFloat/32Integer-4             149.2n ± 2%   148.4n ± 3%        ~ (p=0.450 n=40)
AppendFloat/32ExactFraction-4       247.1n ± 4%   249.9n ± 3%        ~ (p=0.005 n=40)
AppendFloat/32Point-4               231.5n ± 4%   233.9n ± 2%        ~ (p=0.288 n=40)
AppendFloat/32Exp-4                 286.9n ± 3%   284.5n ± 0%        ~ (p=0.015 n=40)
AppendFloat/32NegExp-4              244.5n ± 1%   244.3n ± 4%        ~ (p=0.637 n=40)
AppendFloat/32Shortest-4            227.4n ± 0%   227.2n ± 1%        ~ (p=0.161 n=40)
AppendFloat/32Fixed8Hard-4          146.8n ± 1%   123.7n ± 2%  -15.71% (p=0.000 n=40)
AppendFloat/32Fixed9Hard-4          218.7n ± 3%   204.7n ± 1%   -6.42% (p=0.000 n=40)
AppendFloat/64Fixed1-4              194.3n ± 0%   183.7n ± 3%   -5.51% (p=0.000 n=40)
AppendFloat/64Fixed2-4              184.8n ± 1%   172.8n ± 0%   -6.47% (p=0.000 n=40)
AppendFloat/64Fixed3-4              186.1n ± 3%   174.6n ± 3%   -6.21% (p=0.000 n=40)
AppendFloat/64Fixed4-4              164.9n ± 3%   159.1n ± 3%   -3.55% (p=0.000 n=40)
AppendFloat/64Fixed12-4             233.9n ± 2%   206.7n ± 3%  -11.63% (p=0.000 n=40)
AppendFloat/64Fixed16-4             253.2n ± 4%   201.5n ± 1%  -20.40% (p=0.000 n=40)
AppendFloat/64Fixed12Hard-4         224.0n ± 1%   194.4n ± 1%  -13.23% (p=0.000 n=40)
AppendFloat/64Fixed17Hard-4         282.4n ± 2%   231.5n ± 4%  -18.01% (p=0.000 n=40)
AppendFloat/64Fixed18Hard-4         15.92µ ± 3%   15.73µ ± 2%        ~ (p=0.172 n=40)
AppendFloat/Slowpath64-4            305.2n ± 2%   300.0n ± 3%        ~ (p=0.016 n=40)
AppendFloat/SlowpathDenormal64-4    297.1n ± 2%   294.0n ± 1%        ~ (p=0.075 n=40)
AppendUint-4                       1218.5n ± 1%   946.2n ± 1%  -22.34% (p=0.000 n=40)
AppendUintVarlen/digits=1-4         8.735n ± 2%   9.046n ± 3%   +3.56% (p=0.000 n=40)
AppendUintVarlen/digits=2-4         8.752n ± 1%   8.990n ± 1%   +2.71% (p=0.000 n=40)
AppendUintVarlen/digits=3-4         32.45n ± 2%   21.84n ± 1%  -32.72% (p=0.000 n=40)
AppendUintVarlen/digits=4-4         33.23n ± 1%   23.93n ± 3%  -27.99% (p=0.000 n=40)
AppendUintVarlen/digits=5-4         39.00n ± 3%   27.61n ± 2%  -29.18% (p=0.000 n=40)
AppendUintVarlen/digits=6-4         38.87n ± 2%   28.76n ± 2%  -26.00% (p=0.000 n=40)
AppendUintVarlen/digits=7-4         42.55n ± 1%   31.13n ± 3%  -26.84% (p=0.000 n=40)
AppendUintVarlen/digits=8-4         43.13n ± 3%   33.26n ± 1%  -22.88% (p=0.000 n=40)
AppendUintVarlen/digits=9-4         48.54n ± 3%   36.96n ± 1%  -23.86% (p=0.000 n=40)
AppendUintVarlen/digits=10-4        68.81n ± 1%   51.20n ± 1%  -25.59% (p=0.000 n=40)
AppendUintVarlen/digits=11-4        78.96n ± 1%   52.99n ± 1%  -32.89% (p=0.000 n=40)
AppendUintVarlen/digits=12-4        83.14n ± 2%   55.37n ± 2%  -33.40% (p=0.000 n=40)
AppendUintVarlen/digits=13-4        83.74n ± 1%   57.30n ± 2%  -31.58% (p=0.000 n=40)
AppendUintVarlen/digits=14-4        90.47n ± 1%   58.75n ± 3%  -35.06% (p=0.000 n=40)
AppendUintVarlen/digits=15-4        90.35n ± 3%   61.18n ± 1%  -32.28% (p=0.000 n=40)
AppendUintVarlen/digits=16-4        94.12n ± 1%   63.77n ± 2%  -32.25% (p=0.000 n=40)
AppendUintVarlen/digits=17-4        93.81n ± 0%   64.35n ± 3%  -31.40% (p=0.000 n=40)
AppendUintVarlen/digits=18-4        99.25n ± 1%   67.18n ± 3%  -32.31% (p=0.000 n=40)
AppendUintVarlen/digits=19-4       118.70n ± 0%   81.28n ± 1%  -31.52% (p=0.000 n=40)
AppendUintVarlen/digits=20-4       135.90n ± 1%   83.23n ± 1%  -38.76% (p=0.000 n=40)
geomean                             140.3n        117.7n       -16.12%

Change-Id: If5e2151c397701b23dbc69f20e57b99728898e90
Reviewed-on: https://go-review.googlesource.com/c/go/+/712662
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
Russ Cox 2025-10-17 00:31:09 -04:00
parent e5688d0bdd
commit 8378276d66
3 changed files with 204 additions and 116 deletions

View file

@ -483,7 +483,7 @@ func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
}
// mantissa
dst, _ = formatBits(dst, mant, 10, false, true)
dst = AppendUint(dst, mant, 10)
// p
dst = append(dst, 'p')
@ -493,7 +493,7 @@ func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
if exp >= 0 {
dst = append(dst, '+')
}
dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true)
dst = AppendInt(dst, int64(exp), 10)
return dst
}

View file

@ -192,30 +192,9 @@ func formatDecimal(d *decimalSlice, m uint64, trunc bool, roundUp bool, prec int
m /= 10
trimmed++
}
// render digits (similar to formatBits)
n := uint(prec)
// render digits
formatBase10(d.d[:prec], m)
d.nd = prec
v := m
for v >= 100 {
var v1, v2 uint64
if v>>32 == 0 {
v1, v2 = uint64(uint32(v)/100), uint64(uint32(v)%100)
} else {
v1, v2 = v/100, v%100
}
n -= 2
d.d[n+1] = smallsString[2*v2+1]
d.d[n+0] = smallsString[2*v2+0]
v = v1
}
if v > 0 {
n--
d.d[n] = smallsString[2*v+1]
}
if v >= 10 {
n--
d.d[n] = smallsString[2*v]
}
for d.d[d.nd-1] == '0' {
d.nd--
trimmed++
@ -448,8 +427,8 @@ func ryuDigits32(d *decimalSlice, lower, central, upper uint32,
n := endindex
for n > d.nd {
v1, v2 := v/100, v%100
d.d[n] = smallsString[2*v2+1]
d.d[n-1] = smallsString[2*v2+0]
d.d[n] = smalls[2*v2+1]
d.d[n-1] = smalls[2*v2+0]
n -= 2
v = v1
}
@ -535,7 +514,7 @@ func divisibleByPower5(m uint64, k int) bool {
// divmod1e9 computes quotient and remainder of division by 1e9,
// avoiding runtime uint64 division on 32-bit platforms.
func divmod1e9(x uint64) (uint32, uint32) {
if !host32bit {
if host64bit {
return uint32(x / 1e9), uint32(x % 1e9)
}
// Use the same sequence of operations as the amd64 compiler.

View file

@ -4,17 +4,23 @@
package strconv
import "math/bits"
const fastSmalls = true // enable fast path for small integers
import (
"math/bits"
"runtime"
)
// FormatUint returns the string representation of i in the given base,
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatUint(i uint64, base int) string {
if fastSmalls && i < nSmalls && base == 10 {
if base == 10 {
if i < nSmalls {
return small(int(i))
}
var a [24]byte
j := formatBase10(a[:], i)
return string(a[j:])
}
_, s := formatBits(nil, i, base, false, false)
return s
}
@ -23,9 +29,22 @@ func FormatUint(i uint64, base int) string {
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatInt(i int64, base int) string {
if fastSmalls && 0 <= i && i < nSmalls && base == 10 {
if base == 10 {
if 0 <= i && i < nSmalls {
return small(int(i))
}
var a [24]byte
u := uint64(i)
if i < 0 {
u = -u
}
j := formatBase10(a[:], u)
if i < 0 {
j--
a[j] = '-'
}
return string(a[j:])
}
_, s := formatBits(nil, uint64(i), base, i < 0, false)
return s
}
@ -38,46 +57,29 @@ func Itoa(i int) string {
// AppendInt appends the string form of the integer i,
// as generated by [FormatInt], to dst and returns the extended buffer.
func AppendInt(dst []byte, i int64, base int) []byte {
if fastSmalls && 0 <= i && i < nSmalls && base == 10 {
return append(dst, small(int(i))...)
u := uint64(i)
if i < 0 {
dst = append(dst, '-')
u = -u
}
dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
return dst
return AppendUint(dst, u, base)
}
// AppendUint appends the string form of the unsigned integer i,
// as generated by [FormatUint], to dst and returns the extended buffer.
func AppendUint(dst []byte, i uint64, base int) []byte {
if fastSmalls && i < nSmalls && base == 10 {
if base == 10 {
if i < nSmalls {
return append(dst, small(int(i))...)
}
var a [24]byte
j := formatBase10(a[:], i)
return append(dst, a[j:]...)
}
dst, _ = formatBits(dst, i, base, false, true)
return dst
}
// small returns the string for an i with 0 <= i < nSmalls.
func small(i int) string {
if i < 10 {
return digits[i : i+1]
}
return smallsString[i*2 : i*2+2]
}
const nSmalls = 100
const smallsString = "00010203040506070809" +
"10111213141516171819" +
"20212223242526272829" +
"30313233343536373839" +
"40414243444546474849" +
"50515253545556575859" +
"60616263646566676869" +
"70717273747576777879" +
"80818283848586878889" +
"90919293949596979899"
const host32bit = ^uint(0)>>32 == 0
const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
// formatBits computes the string representation of u in the given base.
@ -85,15 +87,15 @@ const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
// set, the string is appended to dst and the resulting byte slice is
// returned as the first result value; otherwise the string is returned
// as the second result value.
// The caller is expected to have handled base 10 separately for speed.
func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) {
if base < 2 || base > len(digits) {
if base < 2 || base == 10 || base > len(digits) {
panic("strconv: illegal AppendInt/FormatInt base")
}
// 2 <= base && base <= len(digits)
var a [64 + 1]byte // +1 for sign of 64bit value in base 2
i := len(a)
if neg {
u = -u
}
@ -101,56 +103,7 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
// convert bits
// We use uint values where we can because those will
// fit into a single register even on a 32bit machine.
if base == 10 {
// common case: use constants for / because
// the compiler can optimize it into a multiply+shift
if host32bit {
// convert the lower digits using 32bit operations
for u >= 1e9 {
// Avoid using r = a%b in addition to q = a/b
// since 64bit division and modulo operations
// are calculated by runtime functions on 32bit machines.
q := u / 1e9
us := uint(u - q*1e9) // u % 1e9 fits into a uint
for j := 4; j > 0; j-- {
is := us % 100 * 2
us /= 100
i -= 2
a[i+1] = smallsString[is+1]
a[i+0] = smallsString[is+0]
}
// us < 10, since it contains the last digit
// from the initial 9-digit us.
i--
a[i] = smallsString[us*2+1]
u = q
}
// u < 1e9
}
// u guaranteed to fit into a uint
us := uint(u)
for us >= 100 {
is := us % 100 * 2
us /= 100
i -= 2
a[i+1] = smallsString[is+1]
a[i+0] = smallsString[is+0]
}
// us < 100
is := us * 2
i--
a[i] = smallsString[is+1]
if us >= 10 {
i--
a[i] = smallsString[is]
}
} else if isPowerOfTwo(base) {
if isPowerOfTwo(base) {
// Use shifts and masks instead of / and %.
shift := uint(bits.TrailingZeros(uint(base)))
b := uint64(base)
@ -197,3 +150,159 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
func isPowerOfTwo(x int) bool {
return x&(x-1) == 0
}
const nSmalls = 100
// smalls is the formatting of 00..99 concatenated.
// It is then padded out with 56 x's to 256 bytes,
// so that smalls[x&0xFF] has no bounds check.
//
// TODO(rsc): Once the compiler does a better job
// at tracking mod bounds, the &0xFF should not be needed:
// go.dev/issue/75954 and go.dev/issue/63110.
const smalls = "00010203040506070809" +
"10111213141516171819" +
"20212223242526272829" +
"30313233343536373839" +
"40414243444546474849" +
"50515253545556575859" +
"60616263646566676869" +
"70717273747576777879" +
"80818283848586878889" +
"90919293949596979899" +
"xxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxx" +
"xxxxxx"
const host64bit = ^uint(0)>>32 != 0
// small returns the string for an i with 0 <= i < nSmalls.
func small(i int) string {
if i < 10 {
return digits[i : i+1]
}
return smalls[i*2 : i*2+2]
}
// formatBase10 formats the decimal representation of u into the tail of a
// and returns the offset of the first byte written to a. That is, after
//
// i := formatBase10(a, u)
//
// the decimal representation is in a[i:].
func formatBase10(a []byte, u uint64) int {
// Decide implementation strategy based on architecture.
const (
// 64-bit systems can work in 64-bit math the whole time
// or can split the uint64 into uint32-sized chunks.
// On most systems, the uint32 math is faster, but not all.
// The decision here is based on benchmarking.
itoaPure64 = host64bit && runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" && runtime.GOARCH != "s390x"
// 64-bit systems can all use 64-bit div and mod by a constant,
// which the compiler rewrites to use 64x64→128-bit multiplies.
itoaDivMod64 = host64bit // can use 64-bit div/mod by constant
)
if itoaPure64 {
// Convert 2 digits at a time, using 64-bit math.
i := len(a)
u := uint(u)
for u >= 100 {
var dd uint
u, dd = u/100, (u%100)*2
i -= 2
a[i+0], a[i+1] = smalls[(dd+0)&0xFF], smalls[(dd+1)&0xFF]
}
dd := u * 2
i--
a[i] = smalls[(dd+1)&0xFF]
if u >= 10 {
i--
a[i] = smalls[(dd+0)&0xFF]
}
return i
}
// Convert 9-digit chunks using 32-bit math.
// Most numbers are small, so the comparison u >= 1e9 is usually pure overhead,
// so we approximate it by u>>29 != 0, which is usually faster and good enough.
i := len(a)
for (host64bit && u>>29 != 0) || (!host64bit && (u>>32 != 0 || uint32(u)>>29 != 0)) {
var lo uint32
if itoaDivMod64 {
u, lo = u/1e9, uint32(u%1e9)
} else {
// On 64-bit systems the compiler rewrites the div and mod above
// into a 64x64→128-bit multiply (https://godbolt.org/z/EPnK8zvMK):
// hi, _ := bits.Mul64(u>>1, 0x89705f4136b4a598)
// q := hi >> 28
// lo = uint32(u - q*1e9)
// u = q
// On 32-bit systems, the compiler invokes a uint64 software divide,
// which is quite slow. We could write the bits.Mul64 code above
// but even that is slower than we'd like, since it calls a software mul64
// instead of having a hardware instruction to use.
// Instead we inline bits.Mul64 here and change y0/y1 to constants.
// The compiler does use direct 32x32→64-bit multiplies for this code.
//
// For lots more about division by multiplication see Warren, _Hacker's Delight_.
// For a concise overview, see the first two sections of
// https://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html.
const mask32 = 1<<32 - 1
x0 := ((u >> 1) & mask32)
x1 := (u >> 1) >> 32
const y0 = 0x36b4a598
const y1 = 0x89705f41
w0 := x0 * y0
t := x1*y0 + w0>>32
w1 := t & mask32
w2 := t >> 32
w1 += x0 * y1
hi := x1*y1 + w2 + w1>>32
q := hi >> 28
lo = uint32(u) - uint32(q)*1e9 // uint32(u - q*1e9) but faster
u = q
}
// Convert 9 digits.
for range 4 {
var dd uint32
lo, dd = lo/100, (lo%100)*2
i -= 2
a[i+0], a[i+1] = smalls[(dd+0)&0xFF], smalls[(dd+1)&0xFF]
}
i--
a[i] = smalls[(lo*2+1)&0xFF]
// If we'd been using u >= 1e9 then we would be guaranteed that u/1e9 > 0,
// but since we used u>>29 != 0, u/1e9 might be 0, so we might be done.
// (If u is now 0, then at the start we had 2²⁹ ≤ u < 10⁹, so it was still correct
// to write 9 digits; we have not accidentally written any leading zeros.)
if u == 0 {
return i
}
}
// Convert final chunk, at most 8 digits.
lo := uint32(u)
for lo >= 100 {
var dd uint32
lo, dd = lo/100, (lo%100)*2
i -= 2
a[i+0], a[i+1] = smalls[(dd+0)&0xFF], smalls[(dd+1)&0xFF]
}
i--
dd := lo * 2
a[i] = smalls[(dd+1)&0xFF]
if lo >= 10 {
i--
a[i] = smalls[(dd+0)&0xFF]
}
return i
}