2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00

opt: faster ftoa (#291)

* opt: faster f64toa

* feat:(option) add option `MaxInlineDepth` for addjust compilation inline depth (#287)

* feat: make compilation depth changeable

* feat: add option `DefaultMaxInlineDepth`

* add recurse depth = 10

* refactor

* doc: readme and comment

* opt: add `_MAX_FIELDS` to limit the inlining of big struct

* update license

* fix typo

* feat:(ast) support cast `null` to empty value (#278)

* fix: recompile

* test: add ftoa benchmarks

* feat: add f32toa

* fix: add license

* opt: optimize decimal

* fix benchmarks

* fix: poor performance in atof32

* test: add more integer test

Co-authored-by: liuqiang <liuqiang.06@bytedance.com>
Co-authored-by: Yi Duan <duanyi.aster@bytedance.com>
This commit is contained in:
liu 2022-09-20 10:26:18 +08:00 committed by GitHub
parent 2138136685
commit ccc0f3f1e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 20751 additions and 13684 deletions

View file

@ -43,6 +43,7 @@ CFLAGS += -fno-rtti
CFLAGS += -fno-stack-protector CFLAGS += -fno-stack-protector
CFLAGS += -nostdlib CFLAGS += -nostdlib
CFLAGS += -O3 CFLAGS += -O3
CFLAGS += -Wall -Werror
NATIVE_SRC := $(wildcard native/*.h) NATIVE_SRC := $(wildcard native/*.h)
NATIVE_SRC += $(wildcard native/*.c) NATIVE_SRC += $(wildcard native/*.c)

View file

@ -828,11 +828,11 @@ var unmarshalTests = []unmarshalTest{
{in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true}, {in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true},
{in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true}, {in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true},
{in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true}, {in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true},
{in: `1e21`, ptr: new(float64), out: 1e21, golden: true}, {in: `1e+21`, ptr: new(float64), out: 1e21, golden: true},
{in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true}, {in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true},
{in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true}, {in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true},
{in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true}, {in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true},
{in: `-1e21`, ptr: new(float64), out: -1e21, golden: true}, {in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true},
{in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true}, {in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
{in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true}, {in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
{in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false}, {in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},

View file

@ -732,6 +732,7 @@ var (
var ( var (
_F_f64toa = jit.Imm(int64(native.S_f64toa)) _F_f64toa = jit.Imm(int64(native.S_f64toa))
_F_f32toa = jit.Imm(int64(native.S_f32toa))
_F_i64toa = jit.Imm(int64(native.S_i64toa)) _F_i64toa = jit.Imm(int64(native.S_i64toa))
_F_u64toa = jit.Imm(int64(native.S_u64toa)) _F_u64toa = jit.Imm(int64(native.S_u64toa))
_F_b64encode = jit.Imm(int64(_subr__b64encode)) _F_b64encode = jit.Imm(int64(_subr__b64encode))
@ -851,8 +852,7 @@ func (self *_Assembler) _asm_OP_f32(_ *_Instr) {
self.save_c() // SAVE $C_regs self.save_c() // SAVE $C_regs
self.rbuf_di() // MOVQ RP, DI self.rbuf_di() // MOVQ RP, DI
self.Emit("MOVSS" , jit.Ptr(_SP_p, 0), _X0) // MOVSS (SP.p), X0 self.Emit("MOVSS" , jit.Ptr(_SP_p, 0), _X0) // MOVSS (SP.p), X0
self.Emit("CVTSS2SD", _X0, _X0) // CVTSS2SD X0, X0 self.call_c(_F_f32toa) // CALL_C f64toa
self.call_c(_F_f64toa) // CALL_C f64toa
self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL
} }

View file

@ -745,6 +745,7 @@ var (
var ( var (
_F_f64toa = jit.Imm(int64(native.S_f64toa)) _F_f64toa = jit.Imm(int64(native.S_f64toa))
_F_f32toa = jit.Imm(int64(native.S_f32toa))
_F_i64toa = jit.Imm(int64(native.S_i64toa)) _F_i64toa = jit.Imm(int64(native.S_i64toa))
_F_u64toa = jit.Imm(int64(native.S_u64toa)) _F_u64toa = jit.Imm(int64(native.S_u64toa))
_F_b64encode = jit.Imm(int64(_subr__b64encode)) _F_b64encode = jit.Imm(int64(_subr__b64encode))
@ -864,8 +865,7 @@ func (self *_Assembler) _asm_OP_f32(_ *_Instr) {
self.save_c() // SAVE $C_regs self.save_c() // SAVE $C_regs
self.rbuf_di() // MOVQ RP, DI self.rbuf_di() // MOVQ RP, DI
self.Emit("MOVSS" , jit.Ptr(_SP_p, 0), _X0) // MOVSS (SP.p), X0 self.Emit("MOVSS" , jit.Ptr(_SP_p, 0), _X0) // MOVSS (SP.p), X0
self.Emit("CVTSS2SD", _X0, _X0) // CVTSS2SD X0, X0 self.call_c(_F_f32toa) // CALL_C f64toa
self.call_c(_F_f64toa) // CALL_C f64toa
self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL
} }

View file

@ -600,4 +600,84 @@ func BenchmarkCompact_Std(b *testing.B) {
dst.Reset() dst.Reset()
_ = json.Compact(dst, data) _ = json.Compact(dst, data)
} }
}
type f64Bench struct {
name string
float float64
}
func BenchmarkEncoder_Float64(b *testing.B) {
var bench = []f64Bench{
{"Zero", 0},
{"ShortDecimal", 1000},
{"Decimal", 33909},
{"Float", 339.7784},
{"Exp", -5.09e75},
{"NegExp", -5.11e-95},
{"LongExp", 1.234567890123456e-78},
{"Big", 123456789123456789123456789},
}
maxUint := "18446744073709551615"
for i := 1; i <= len(maxUint); i++ {
name := strconv.FormatInt(int64(i), 10) + "-Digs"
num, _ := strconv.ParseUint(string(maxUint[:i]), 10, 64)
bench = append(bench, f64Bench{name, float64(num)})
}
for _, c := range bench {
libs := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { _, _ = json.Marshal(c.float); for i := 0; i < b.N; i++ { _, _ = json.Marshal(c.float) }},
}, {
name: "Sonic",
test: func(b *testing.B) { _, _ = Encode(c.float, 0); for i := 0; i < b.N; i++ { _, _ = Encode(c.float, 0) }},
}}
for _, lib := range libs {
name := lib.name + "_" + c.name
b.Run(name, lib.test)
}
}
}
type f32Bench struct {
name string
float float32
}
func BenchmarkEncoder_Float32(b *testing.B) {
var bench = []f32Bench{
{"Zero", 0},
{"ShortDecimal", 1000},
{"Decimal", 33909},
{"ExactFraction", 3.375},
{"Point", 339.7784},
{"Exp", -5.09e25},
{"NegExp", -5.11e-25},
{"Shortest", 1.234567e-8},
}
maxUint := "18446744073709551615"
for i := 1; i <= len(maxUint); i++ {
name := strconv.FormatInt(int64(i), 10) + "-Digs"
num, _ := strconv.ParseUint(string(maxUint[:i]), 10, 64)
bench = append(bench, f32Bench{name, float32(num)})
}
for _, c := range bench {
libs := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { _, _ = json.Marshal(c.float); for i := 0; i < b.N; i++ { _, _ = json.Marshal(c.float) }},
}, {
name: "Sonic",
test: func(b *testing.B) { _, _ = Encode(c.float, 0); for i := 0; i < b.N; i++ { _, _ = Encode(c.float, 0) }},
}}
for _, lib := range libs {
name := lib.name + "_" + c.name
b.Run(name, lib.test)
}
}
} }

View file

@ -82,11 +82,18 @@ func fuzzMain(t *testing.T, data []byte) {
jout, jerr := json.Marshal(jv) jout, jerr := json.Marshal(jv)
require.NoError(t, serr, "error in sonic marshal %v", reflect.TypeOf(jv)) require.NoError(t, serr, "error in sonic marshal %v", reflect.TypeOf(jv))
require.NoError(t, jerr, "error in json marshal %v", reflect.TypeOf(jv)) require.NoError(t, jerr, "error in json marshal %v", reflect.TypeOf(jv))
// not comparing here because sonic marshal is different from encoding/json, as:
// case 1: 1.23e2 -> `1.23e2` in sonic, but 1.23e2 -> `1.23e+2` in encoding/json {
// case 2: "\b" -> `\\b` in sonic, but `\u0008` in encoding/json sv, jv := typ(), typ()
// require.Equal(t, sout, jout, "different in sonic marshal %v", reflect.TypeOf(jv)) serr := sonic.Unmarshal(sout, sv)
var _, _ = sout, jout jerr := json.Unmarshal(jout, jv)
require.Equalf(t, serr != nil, jerr != nil, "different error in sonic unmarshal again %v", reflect.TypeOf(jv))
if jerr != nil {
return
}
require.Equal(t, sv, jv, "different result in sonic unmarshal again %v", reflect.TypeOf(jv))
}
if m, ok := sv.(*map[string]interface{}); ok { if m, ok := sv.(*map[string]interface{}); ok {
fuzzDynamicStruct(t, jout, *m) fuzzDynamicStruct(t, jout, *m)
fuzzASTGetFromObject(t, jout, *m) fuzzASTGetFromObject(t, jout, *m)

View file

@ -22,6 +22,8 @@ import (
`math` `math`
`strconv` `strconv`
`testing` `testing`
`math/rand`
`encoding/json`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -33,52 +35,106 @@ func TestFastFloat_Encode(t *testing.T) {
assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)])) assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)]))
assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)])) assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)]))
assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)])) assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)]))
assert.Equal(t, "1e30" , string(buf[:__f64toa(&buf[0], 1e30)])) assert.Equal(t, "1e+30" , string(buf[:__f64toa(&buf[0], 1e30)]))
assert.Equal(t, "1.234e33" , string(buf[:__f64toa(&buf[0], 1234e30)])) assert.Equal(t, "1.234e+33" , string(buf[:__f64toa(&buf[0], 1234e30)]))
assert.Equal(t, "1.234e308" , string(buf[:__f64toa(&buf[0], 1234e305)])) assert.Equal(t, "1.234e+308" , string(buf[:__f64toa(&buf[0], 1234e305)]))
assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)])) assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)]))
assert.Equal(t, "1.7976931348623157e308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)])) assert.Equal(t, "1.7976931348623157e+308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)]))
assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)])) assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)]))
assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)])) assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)]))
assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)])) assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)]))
assert.Equal(t, "-1e30" , string(buf[:__f64toa(&buf[0], -1e30)])) assert.Equal(t, "-1e+30" , string(buf[:__f64toa(&buf[0], -1e30)]))
assert.Equal(t, "-1.234e33" , string(buf[:__f64toa(&buf[0], -1234e30)])) assert.Equal(t, "-1.234e+33" , string(buf[:__f64toa(&buf[0], -1234e30)]))
assert.Equal(t, "-1.234e308" , string(buf[:__f64toa(&buf[0], -1234e305)])) assert.Equal(t, "-1.234e+308" , string(buf[:__f64toa(&buf[0], -1234e305)]))
assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)])) assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)]))
assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)])) assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)]))
} }
func BenchmarkFastFloat_Encode(b *testing.B) { func TestFastFloat_Random(t *testing.T) {
val := -2.2250738585072014e-308 var buf [64]byte
benchmarks := []struct { N := 10000
name string for i := 0; i < N; i++ {
test func(*testing.B) b64 := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
}{{ f64 := math.Float64frombits(b64)
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, jout, jerr := json.Marshal(f64)
}, { n := __f64toa(&buf[0], f64)
name: "FastFloat", if jerr == nil {
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, assert.Equal(t, jout, buf[:n])
}} } else {
for _, bm := range benchmarks { assert.True(t, n == 0)
b.Run(bm.name, bm.test) }
f32 := math.Float32frombits(rand.Uint32())
jout, jerr = json.Marshal(f32)
n = __f32toa(&buf[0], f32)
if jerr == nil {
assert.Equal(t, jout, buf[:n])
} else {
assert.True(t, n == 0)
}
} }
} }
func BenchmarkFastFloat_EncodeZero(b *testing.B) { func BenchmarkParseFloat64(b *testing.B) {
val := float64(0) var f64toaBenches = []struct {
benchmarks := []struct { name string
name string float float64
test func(*testing.B) }{
}{{ {"Zero", 0},
name: "StdLib", {"Decimal", 33909},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, {"Float", 339.7784},
}, { {"Exp", -5.09e75},
name: "FastFloat", {"NegExp", -5.11e-95},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, {"LongExp", 1.234567890123456e-78},
}} {"Big", 123456789123456789123456789},
for _, bm := range benchmarks {
b.Run(bm.name, bm.test) }
for _, c := range f64toaBenches {
f64bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], c.float, 'g', -1, 64) }},
}, {
name: "FastFloat",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], c.float) }},
}}
for _, bm := range f64bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
} }
} }
func BenchmarkParseFloat32(b *testing.B) {
var f32toaBenches = []struct {
name string
float float32
}{
{"Zero", 0},
{"Integer", 33909},
{"ExactFraction", 3.375},
{"Point", 339.7784},
{"Exp", -5.09e25},
{"NegExp", -5.11e-25},
{"Shortest", 1.234567e-8},
}
for _, c := range f32toaBenches {
bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], float64(c.float), 'g', -1, 32) }},
}, {
name: "FastFloat32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f32toa(&buf[0], c.float) }},
}}
for _, bm := range bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
}
}

View file

@ -21,6 +21,7 @@ package avx
import ( import (
`strconv` `strconv`
`testing` `testing`
`fmt`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -96,40 +97,57 @@ func TestFastInt_UintToString(t *testing.T) {
assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)])) assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)]))
} }
func BenchmarkFastInt_IntToString(b *testing.B) { func BenchmarkFastInt_IntToString(b *testing.B) {
benchmarks := []struct { benchmarks := []struct {
name string name string
test func(*testing.B) test func(*testing.B)
}{{ }{{
name: "StdLib-Positive", name: "StdLib-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], int64(i), 10) }},
}, { }, {
name: "StdLib-Negative", name: "StdLib-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], -int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], -int64(i), 10) }},
}, { }, {
name: "FastInt-Positive", name: "FastInt-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }},
}, { }, {
name: "FastInt-Negative", name: "FastInt-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }},
}} }}
for _, bm := range benchmarks { for _, bm := range benchmarks {
b.Run(bm.name, bm.test) b.Run(bm.name, bm.test)
} }
} }
func BenchmarkFastInt_UintToString(b *testing.B) { type utoaBench struct {
benchmarks := []struct { name string
name string num uint64
test func(*testing.B) }
}{{
name: "StdLib", func BenchmarkFastInt_UintToString(b *testing.B) {
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:], uint64(i), 10) }}, maxUint := "18446744073709551615"
}, { benchs := make([]utoaBench, len(maxUint) + 1)
name: "FastInt", benchs[0].name = "Zero"
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], uint64(i)) }}, benchs[0].num = 0
}} for i := 1; i <= len(maxUint); i++ {
for _, bm := range benchmarks { benchs[i].name = strconv.FormatInt(int64(i), 10) + "-Digs"
b.Run(bm.name, bm.test) benchs[i].num, _ = strconv.ParseUint(string(maxUint[:i]), 10, 64)
} }
}
for _, t := range(benchs) {
benchmarks := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:0], t.num, 10) }},
}, {
name: "FastInt",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], t.num) }},
}}
for _, bm := range benchmarks {
name := fmt.Sprintf("%s_%s", bm.name, t.name)
b.Run(name, bm.test)
}
}
}

View file

@ -39,6 +39,11 @@ func __u64toa(out *byte, val uint64) (ret int)
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int) func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit //go:nosplit
//go:noescape //go:noescape
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@ package avx
var ( var (
S_f64toa = _subr__f64toa S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa S_u64toa = _subr__u64toa
S_lspace = _subr__lspace S_lspace = _subr__lspace

View file

@ -9,28 +9,30 @@ package avx
func __native_entry__() uintptr func __native_entry__() uintptr
var ( var (
_subr__f64toa = __native_entry__() + 704 _subr__f32toa = __native_entry__() + 24880
_subr__html_escape = __native_entry__() + 9920 _subr__f64toa = __native_entry__() + 720
_subr__i64toa = __native_entry__() + 3616 _subr__html_escape = __native_entry__() + 10768
_subr__i64toa = __native_entry__() + 4464
_subr__lspace = __native_entry__() + 320 _subr__lspace = __native_entry__() + 320
_subr__lzero = __native_entry__() + 16 _subr__lzero = __native_entry__() + 16
_subr__quote = __native_entry__() + 4992 _subr__quote = __native_entry__() + 5840
_subr__skip_array = __native_entry__() + 22304 _subr__skip_array = __native_entry__() + 23152
_subr__skip_number = __native_entry__() + 23776 _subr__skip_number = __native_entry__() + 24624
_subr__skip_object = __native_entry__() + 22352 _subr__skip_object = __native_entry__() + 23200
_subr__skip_one = __native_entry__() + 20432 _subr__skip_one = __native_entry__() + 21280
_subr__u64toa = __native_entry__() + 3728 _subr__u64toa = __native_entry__() + 4576
_subr__unquote = __native_entry__() + 6736 _subr__unquote = __native_entry__() + 7584
_subr__validate_one = __native_entry__() + 23920 _subr__validate_one = __native_entry__() + 24768
_subr__value = __native_entry__() + 13168 _subr__value = __native_entry__() + 14016
_subr__vnumber = __native_entry__() + 18176 _subr__vnumber = __native_entry__() + 19024
_subr__vsigned = __native_entry__() + 19728 _subr__vsigned = __native_entry__() + 20576
_subr__vstring = __native_entry__() + 15248 _subr__vstring = __native_entry__() + 16096
_subr__vunsigned = __native_entry__() + 20080 _subr__vunsigned = __native_entry__() + 20928
) )
const ( const (
_stack__f64toa = 128 _stack__f32toa = 728
_stack__f64toa = 712
_stack__html_escape = 64 _stack__html_escape = 64
_stack__i64toa = 16 _stack__i64toa = 16
_stack__lspace = 8 _stack__lspace = 8
@ -51,6 +53,7 @@ const (
) )
var ( var (
_ = _subr__f32toa
_ = _subr__f64toa _ = _subr__f64toa
_ = _subr__html_escape _ = _subr__html_escape
_ = _subr__i64toa _ = _subr__i64toa
@ -72,6 +75,7 @@ var (
) )
const ( const (
_ = _stack__f32toa
_ = _stack__f64toa _ = _stack__f64toa
_ = _stack__html_escape _ = _stack__html_escape
_ = _stack__i64toa _ = _stack__i64toa

View file

@ -22,6 +22,8 @@ import (
`math` `math`
`strconv` `strconv`
`testing` `testing`
`math/rand`
`encoding/json`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -33,52 +35,106 @@ func TestFastFloat_Encode(t *testing.T) {
assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)])) assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)]))
assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)])) assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)]))
assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)])) assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)]))
assert.Equal(t, "1e30" , string(buf[:__f64toa(&buf[0], 1e30)])) assert.Equal(t, "1e+30" , string(buf[:__f64toa(&buf[0], 1e30)]))
assert.Equal(t, "1.234e33" , string(buf[:__f64toa(&buf[0], 1234e30)])) assert.Equal(t, "1.234e+33" , string(buf[:__f64toa(&buf[0], 1234e30)]))
assert.Equal(t, "1.234e308" , string(buf[:__f64toa(&buf[0], 1234e305)])) assert.Equal(t, "1.234e+308" , string(buf[:__f64toa(&buf[0], 1234e305)]))
assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)])) assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)]))
assert.Equal(t, "1.7976931348623157e308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)])) assert.Equal(t, "1.7976931348623157e+308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)]))
assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)])) assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)]))
assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)])) assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)]))
assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)])) assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)]))
assert.Equal(t, "-1e30" , string(buf[:__f64toa(&buf[0], -1e30)])) assert.Equal(t, "-1e+30" , string(buf[:__f64toa(&buf[0], -1e30)]))
assert.Equal(t, "-1.234e33" , string(buf[:__f64toa(&buf[0], -1234e30)])) assert.Equal(t, "-1.234e+33" , string(buf[:__f64toa(&buf[0], -1234e30)]))
assert.Equal(t, "-1.234e308" , string(buf[:__f64toa(&buf[0], -1234e305)])) assert.Equal(t, "-1.234e+308" , string(buf[:__f64toa(&buf[0], -1234e305)]))
assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)])) assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)]))
assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)])) assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)]))
} }
func BenchmarkFastFloat_Encode(b *testing.B) { func TestFastFloat_Random(t *testing.T) {
val := -2.2250738585072014e-308 var buf [64]byte
benchmarks := []struct { N := 10000
name string for i := 0; i < N; i++ {
test func(*testing.B) b64 := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
}{{ f64 := math.Float64frombits(b64)
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, jout, jerr := json.Marshal(f64)
}, { n := __f64toa(&buf[0], f64)
name: "FastFloat", if jerr == nil {
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, assert.Equal(t, jout, buf[:n])
}} } else {
for _, bm := range benchmarks { assert.True(t, n == 0)
b.Run(bm.name, bm.test) }
f32 := math.Float32frombits(rand.Uint32())
jout, jerr = json.Marshal(f32)
n = __f32toa(&buf[0], f32)
if jerr == nil {
assert.Equal(t, jout, buf[:n])
} else {
assert.True(t, n == 0)
}
} }
} }
func BenchmarkFastFloat_EncodeZero(b *testing.B) { func BenchmarkParseFloat64(b *testing.B) {
val := float64(0) var f64toaBenches = []struct {
benchmarks := []struct { name string
name string float float64
test func(*testing.B) }{
}{{ {"Zero", 0},
name: "StdLib", {"Decimal", 33909},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, {"Float", 339.7784},
}, { {"Exp", -5.09e75},
name: "FastFloat", {"NegExp", -5.11e-95},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, {"LongExp", 1.234567890123456e-78},
}} {"Big", 123456789123456789123456789},
for _, bm := range benchmarks {
b.Run(bm.name, bm.test) }
for _, c := range f64toaBenches {
f64bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], c.float, 'g', -1, 64) }},
}, {
name: "FastFloat",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], c.float) }},
}}
for _, bm := range f64bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
} }
} }
func BenchmarkParseFloat32(b *testing.B) {
var f32toaBenches = []struct {
name string
float float32
}{
{"Zero", 0},
{"Integer", 33909},
{"ExactFraction", 3.375},
{"Point", 339.7784},
{"Exp", -5.09e25},
{"NegExp", -5.11e-25},
{"Shortest", 1.234567e-8},
}
for _, c := range f32toaBenches {
bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], float64(c.float), 'g', -1, 32) }},
}, {
name: "FastFloat32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f32toa(&buf[0], c.float) }},
}}
for _, bm := range bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
}
}

View file

@ -21,6 +21,7 @@ package avx2
import ( import (
`strconv` `strconv`
`testing` `testing`
`fmt`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -96,40 +97,57 @@ func TestFastInt_UintToString(t *testing.T) {
assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)])) assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)]))
} }
func BenchmarkFastInt_IntToString(b *testing.B) { func BenchmarkFastInt_IntToString(b *testing.B) {
benchmarks := []struct { benchmarks := []struct {
name string name string
test func(*testing.B) test func(*testing.B)
}{{ }{{
name: "StdLib-Positive", name: "StdLib-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], int64(i), 10) }},
}, { }, {
name: "StdLib-Negative", name: "StdLib-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], -int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], -int64(i), 10) }},
}, { }, {
name: "FastInt-Positive", name: "FastInt-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }},
}, { }, {
name: "FastInt-Negative", name: "FastInt-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }},
}} }}
for _, bm := range benchmarks { for _, bm := range benchmarks {
b.Run(bm.name, bm.test) b.Run(bm.name, bm.test)
} }
} }
func BenchmarkFastInt_UintToString(b *testing.B) { type utoaBench struct {
benchmarks := []struct { name string
name string num uint64
test func(*testing.B) }
}{{
name: "StdLib", func BenchmarkFastInt_UintToString(b *testing.B) {
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:], uint64(i), 10) }}, maxUint := "18446744073709551615"
}, { benchs := make([]utoaBench, len(maxUint) + 1)
name: "FastInt", benchs[0].name = "Zero"
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], uint64(i)) }}, benchs[0].num = 0
}} for i := 1; i <= len(maxUint); i++ {
for _, bm := range benchmarks { benchs[i].name = strconv.FormatInt(int64(i), 10) + "-Digs"
b.Run(bm.name, bm.test) benchs[i].num, _ = strconv.ParseUint(string(maxUint[:i]), 10, 64)
} }
}
for _, t := range(benchs) {
benchmarks := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:0], t.num, 10) }},
}, {
name: "FastInt",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], t.num) }},
}}
for _, bm := range benchmarks {
name := fmt.Sprintf("%s_%s", bm.name, t.name)
b.Run(name, bm.test)
}
}
}

View file

@ -39,6 +39,11 @@ func __u64toa(out *byte, val uint64) (ret int)
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int) func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit //go:nosplit
//go:noescape //go:noescape
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@ package avx2
var ( var (
S_f64toa = _subr__f64toa S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa S_u64toa = _subr__u64toa
S_lspace = _subr__lspace S_lspace = _subr__lspace

View file

@ -9,28 +9,30 @@ package avx2
func __native_entry__() uintptr func __native_entry__() uintptr
var ( var (
_subr__f64toa = __native_entry__() + 960 _subr__f32toa = __native_entry__() + 28752
_subr__html_escape = __native_entry__() + 11776 _subr__f64toa = __native_entry__() + 976
_subr__i64toa = __native_entry__() + 3872 _subr__html_escape = __native_entry__() + 12608
_subr__i64toa = __native_entry__() + 4720
_subr__lspace = __native_entry__() + 448 _subr__lspace = __native_entry__() + 448
_subr__lzero = __native_entry__() + 16 _subr__lzero = __native_entry__() + 16
_subr__quote = __native_entry__() + 5360 _subr__quote = __native_entry__() + 6192
_subr__skip_array = __native_entry__() + 25568 _subr__skip_array = __native_entry__() + 26400
_subr__skip_number = __native_entry__() + 27664 _subr__skip_number = __native_entry__() + 28496
_subr__skip_object = __native_entry__() + 25616 _subr__skip_object = __native_entry__() + 26448
_subr__skip_one = __native_entry__() + 23664 _subr__skip_one = __native_entry__() + 24496
_subr__u64toa = __native_entry__() + 3984 _subr__u64toa = __native_entry__() + 4832
_subr__unquote = __native_entry__() + 8304 _subr__unquote = __native_entry__() + 9136
_subr__validate_one = __native_entry__() + 27808 _subr__validate_one = __native_entry__() + 28640
_subr__value = __native_entry__() + 16352 _subr__value = __native_entry__() + 17184
_subr__vnumber = __native_entry__() + 21408 _subr__vnumber = __native_entry__() + 22240
_subr__vsigned = __native_entry__() + 22960 _subr__vsigned = __native_entry__() + 23792
_subr__vstring = __native_entry__() + 18736 _subr__vstring = __native_entry__() + 19568
_subr__vunsigned = __native_entry__() + 23312 _subr__vunsigned = __native_entry__() + 24144
) )
const ( const (
_stack__f64toa = 128 _stack__f32toa = 728
_stack__f64toa = 712
_stack__html_escape = 72 _stack__html_escape = 72
_stack__i64toa = 16 _stack__i64toa = 16
_stack__lspace = 8 _stack__lspace = 8
@ -51,6 +53,7 @@ const (
) )
var ( var (
_ = _subr__f32toa
_ = _subr__f64toa _ = _subr__f64toa
_ = _subr__html_escape _ = _subr__html_escape
_ = _subr__i64toa _ = _subr__i64toa
@ -72,6 +75,7 @@ var (
) )
const ( const (
_ = _stack__f32toa
_ = _stack__f64toa _ = _stack__f64toa
_ = _stack__html_escape _ = _stack__html_escape
_ = _stack__i64toa _ = _stack__i64toa

View file

@ -30,6 +30,7 @@ const MaxFrameSize uintptr = 400
var ( var (
S_f64toa uintptr S_f64toa uintptr
S_f32toa uintptr
S_i64toa uintptr S_i64toa uintptr
S_u64toa uintptr S_u64toa uintptr
S_lspace uintptr S_lspace uintptr
@ -97,6 +98,7 @@ func U64toa(out *byte, val uint64) (ret int)
func useAVX() { func useAVX() {
S_f64toa = avx.S_f64toa S_f64toa = avx.S_f64toa
S_f32toa = avx.S_f32toa
S_i64toa = avx.S_i64toa S_i64toa = avx.S_i64toa
S_u64toa = avx.S_u64toa S_u64toa = avx.S_u64toa
S_lspace = avx.S_lspace S_lspace = avx.S_lspace
@ -115,6 +117,7 @@ func useAVX() {
func useAVX2() { func useAVX2() {
S_f64toa = avx2.S_f64toa S_f64toa = avx2.S_f64toa
S_f32toa = avx2.S_f32toa
S_i64toa = avx2.S_i64toa S_i64toa = avx2.S_i64toa
S_u64toa = avx2.S_u64toa S_u64toa = avx2.S_u64toa
S_lspace = avx2.S_lspace S_lspace = avx2.S_lspace
@ -133,6 +136,7 @@ func useAVX2() {
func useSSE4() { func useSSE4() {
S_f64toa = sse4.S_f64toa S_f64toa = sse4.S_f64toa
S_f32toa = sse4.S_f32toa
S_i64toa = sse4.S_i64toa S_i64toa = sse4.S_i64toa
S_u64toa = sse4.S_u64toa S_u64toa = sse4.S_u64toa
S_lspace = sse4.S_lspace S_lspace = sse4.S_lspace

View file

@ -20,6 +20,8 @@ import (
`math` `math`
`strconv` `strconv`
`testing` `testing`
`math/rand`
`encoding/json`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -31,52 +33,106 @@ func TestFastFloat_Encode(t *testing.T) {
assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)])) assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)]))
assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)])) assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)]))
assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)])) assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)]))
assert.Equal(t, "1e30" , string(buf[:__f64toa(&buf[0], 1e30)])) assert.Equal(t, "1e+30" , string(buf[:__f64toa(&buf[0], 1e30)]))
assert.Equal(t, "1.234e33" , string(buf[:__f64toa(&buf[0], 1234e30)])) assert.Equal(t, "1.234e+33" , string(buf[:__f64toa(&buf[0], 1234e30)]))
assert.Equal(t, "1.234e308" , string(buf[:__f64toa(&buf[0], 1234e305)])) assert.Equal(t, "1.234e+308" , string(buf[:__f64toa(&buf[0], 1234e305)]))
assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)])) assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)]))
assert.Equal(t, "1.7976931348623157e308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)])) assert.Equal(t, "1.7976931348623157e+308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)]))
assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)])) assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)]))
assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)])) assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)]))
assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)])) assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)]))
assert.Equal(t, "-1e30" , string(buf[:__f64toa(&buf[0], -1e30)])) assert.Equal(t, "-1e+30" , string(buf[:__f64toa(&buf[0], -1e30)]))
assert.Equal(t, "-1.234e33" , string(buf[:__f64toa(&buf[0], -1234e30)])) assert.Equal(t, "-1.234e+33" , string(buf[:__f64toa(&buf[0], -1234e30)]))
assert.Equal(t, "-1.234e308" , string(buf[:__f64toa(&buf[0], -1234e305)])) assert.Equal(t, "-1.234e+308" , string(buf[:__f64toa(&buf[0], -1234e305)]))
assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)])) assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)]))
assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)])) assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)]))
} }
func BenchmarkFastFloat_Encode(b *testing.B) { func TestFastFloat_Random(t *testing.T) {
val := -2.2250738585072014e-308 var buf [64]byte
benchmarks := []struct { N := 10000
name string for i := 0; i < N; i++ {
test func(*testing.B) b64 := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
}{{ f64 := math.Float64frombits(b64)
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, jout, jerr := json.Marshal(f64)
}, { n := __f64toa(&buf[0], f64)
name: "FastFloat", if jerr == nil {
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, assert.Equal(t, jout, buf[:n])
}} } else {
for _, bm := range benchmarks { assert.True(t, n == 0)
b.Run(bm.name, bm.test) }
f32 := math.Float32frombits(rand.Uint32())
jout, jerr = json.Marshal(f32)
n = __f32toa(&buf[0], f32)
if jerr == nil {
assert.Equal(t, jout, buf[:n])
} else {
assert.True(t, n == 0)
}
} }
} }
func BenchmarkFastFloat_EncodeZero(b *testing.B) { func BenchmarkParseFloat64(b *testing.B) {
val := float64(0) var f64toaBenches = []struct {
benchmarks := []struct { name string
name string float float64
test func(*testing.B) }{
}{{ {"Zero", 0},
name: "StdLib", {"Decimal", 33909},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, {"Float", 339.7784},
}, { {"Exp", -5.09e75},
name: "FastFloat", {"NegExp", -5.11e-95},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, {"LongExp", 1.234567890123456e-78},
}} {"Big", 123456789123456789123456789},
for _, bm := range benchmarks {
b.Run(bm.name, bm.test) }
for _, c := range f64toaBenches {
f64bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], c.float, 'g', -1, 64) }},
}, {
name: "FastFloat",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], c.float) }},
}}
for _, bm := range f64bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
} }
} }
func BenchmarkParseFloat32(b *testing.B) {
var f32toaBenches = []struct {
name string
float float32
}{
{"Zero", 0},
{"Integer", 33909},
{"ExactFraction", 3.375},
{"Point", 339.7784},
{"Exp", -5.09e25},
{"NegExp", -5.11e-25},
{"Shortest", 1.234567e-8},
}
for _, c := range f32toaBenches {
bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], float64(c.float), 'g', -1, 32) }},
}, {
name: "FastFloat32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f32toa(&buf[0], c.float) }},
}}
for _, bm := range bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
}
}

View file

@ -19,6 +19,7 @@ package {{PACKAGE}}
import ( import (
`strconv` `strconv`
`testing` `testing`
`fmt`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -94,40 +95,57 @@ func TestFastInt_UintToString(t *testing.T) {
assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)])) assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)]))
} }
func BenchmarkFastInt_IntToString(b *testing.B) { func BenchmarkFastInt_IntToString(b *testing.B) {
benchmarks := []struct { benchmarks := []struct {
name string name string
test func(*testing.B) test func(*testing.B)
}{{ }{{
name: "StdLib-Positive", name: "StdLib-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], int64(i), 10) }},
}, { }, {
name: "StdLib-Negative", name: "StdLib-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], -int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], -int64(i), 10) }},
}, { }, {
name: "FastInt-Positive", name: "FastInt-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }},
}, { }, {
name: "FastInt-Negative", name: "FastInt-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }},
}} }}
for _, bm := range benchmarks { for _, bm := range benchmarks {
b.Run(bm.name, bm.test) b.Run(bm.name, bm.test)
} }
} }
func BenchmarkFastInt_UintToString(b *testing.B) { type utoaBench struct {
benchmarks := []struct { name string
name string num uint64
test func(*testing.B) }
}{{
name: "StdLib", func BenchmarkFastInt_UintToString(b *testing.B) {
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:], uint64(i), 10) }}, maxUint := "18446744073709551615"
}, { benchs := make([]utoaBench, len(maxUint) + 1)
name: "FastInt", benchs[0].name = "Zero"
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], uint64(i)) }}, benchs[0].num = 0
}} for i := 1; i <= len(maxUint); i++ {
for _, bm := range benchmarks { benchs[i].name = strconv.FormatInt(int64(i), 10) + "-Digs"
b.Run(bm.name, bm.test) benchs[i].num, _ = strconv.ParseUint(string(maxUint[:i]), 10, 64)
} }
}
for _, t := range(benchs) {
benchmarks := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:0], t.num, 10) }},
}, {
name: "FastInt",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], t.num) }},
}}
for _, bm := range benchmarks {
name := fmt.Sprintf("%s_%s", bm.name, t.name)
b.Run(name, bm.test)
}
}
}

View file

@ -37,6 +37,11 @@ func __u64toa(out *byte, val uint64) (ret int)
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int) func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit //go:nosplit
//go:noescape //go:noescape
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter

View file

@ -18,6 +18,7 @@ package {{PACKAGE}}
var ( var (
S_f64toa = _subr__f64toa S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa S_u64toa = _subr__u64toa
S_lspace = _subr__lspace S_lspace = _subr__lspace

View file

@ -22,6 +22,8 @@ import (
`math` `math`
`strconv` `strconv`
`testing` `testing`
`math/rand`
`encoding/json`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -33,52 +35,106 @@ func TestFastFloat_Encode(t *testing.T) {
assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)])) assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)]))
assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)])) assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)]))
assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)])) assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)]))
assert.Equal(t, "1e30" , string(buf[:__f64toa(&buf[0], 1e30)])) assert.Equal(t, "1e+30" , string(buf[:__f64toa(&buf[0], 1e30)]))
assert.Equal(t, "1.234e33" , string(buf[:__f64toa(&buf[0], 1234e30)])) assert.Equal(t, "1.234e+33" , string(buf[:__f64toa(&buf[0], 1234e30)]))
assert.Equal(t, "1.234e308" , string(buf[:__f64toa(&buf[0], 1234e305)])) assert.Equal(t, "1.234e+308" , string(buf[:__f64toa(&buf[0], 1234e305)]))
assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)])) assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)]))
assert.Equal(t, "1.7976931348623157e308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)])) assert.Equal(t, "1.7976931348623157e+308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)]))
assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)])) assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)]))
assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)])) assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)]))
assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)])) assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)]))
assert.Equal(t, "-1e30" , string(buf[:__f64toa(&buf[0], -1e30)])) assert.Equal(t, "-1e+30" , string(buf[:__f64toa(&buf[0], -1e30)]))
assert.Equal(t, "-1.234e33" , string(buf[:__f64toa(&buf[0], -1234e30)])) assert.Equal(t, "-1.234e+33" , string(buf[:__f64toa(&buf[0], -1234e30)]))
assert.Equal(t, "-1.234e308" , string(buf[:__f64toa(&buf[0], -1234e305)])) assert.Equal(t, "-1.234e+308" , string(buf[:__f64toa(&buf[0], -1234e305)]))
assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)])) assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)]))
assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)])) assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)]))
} }
func BenchmarkFastFloat_Encode(b *testing.B) { func TestFastFloat_Random(t *testing.T) {
val := -2.2250738585072014e-308 var buf [64]byte
benchmarks := []struct { N := 10000
name string for i := 0; i < N; i++ {
test func(*testing.B) b64 := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
}{{ f64 := math.Float64frombits(b64)
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, jout, jerr := json.Marshal(f64)
}, { n := __f64toa(&buf[0], f64)
name: "FastFloat", if jerr == nil {
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, assert.Equal(t, jout, buf[:n])
}} } else {
for _, bm := range benchmarks { assert.True(t, n == 0)
b.Run(bm.name, bm.test) }
f32 := math.Float32frombits(rand.Uint32())
jout, jerr = json.Marshal(f32)
n = __f32toa(&buf[0], f32)
if jerr == nil {
assert.Equal(t, jout, buf[:n])
} else {
assert.True(t, n == 0)
}
} }
} }
func BenchmarkFastFloat_EncodeZero(b *testing.B) { func BenchmarkParseFloat64(b *testing.B) {
val := float64(0) var f64toaBenches = []struct {
benchmarks := []struct { name string
name string float float64
test func(*testing.B) }{
}{{ {"Zero", 0},
name: "StdLib", {"Decimal", 33909},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:], val, 'g', -1, 64) }}, {"Float", 339.7784},
}, { {"Exp", -5.09e75},
name: "FastFloat", {"NegExp", -5.11e-95},
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }}, {"LongExp", 1.234567890123456e-78},
}} {"Big", 123456789123456789123456789},
for _, bm := range benchmarks {
b.Run(bm.name, bm.test) }
for _, c := range f64toaBenches {
f64bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], c.float, 'g', -1, 64) }},
}, {
name: "FastFloat",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], c.float) }},
}}
for _, bm := range f64bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
} }
} }
func BenchmarkParseFloat32(b *testing.B) {
var f32toaBenches = []struct {
name string
float float32
}{
{"Zero", 0},
{"Integer", 33909},
{"ExactFraction", 3.375},
{"Point", 339.7784},
{"Exp", -5.09e25},
{"NegExp", -5.11e-25},
{"Shortest", 1.234567e-8},
}
for _, c := range f32toaBenches {
bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], float64(c.float), 'g', -1, 32) }},
}, {
name: "FastFloat32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f32toa(&buf[0], c.float) }},
}}
for _, bm := range bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
}
}

View file

@ -21,6 +21,7 @@ package sse4
import ( import (
`strconv` `strconv`
`testing` `testing`
`fmt`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
@ -96,40 +97,57 @@ func TestFastInt_UintToString(t *testing.T) {
assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)])) assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)]))
} }
func BenchmarkFastInt_IntToString(b *testing.B) { func BenchmarkFastInt_IntToString(b *testing.B) {
benchmarks := []struct { benchmarks := []struct {
name string name string
test func(*testing.B) test func(*testing.B)
}{{ }{{
name: "StdLib-Positive", name: "StdLib-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], int64(i), 10) }},
}, { }, {
name: "StdLib-Negative", name: "StdLib-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:], -int64(i), 10) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], -int64(i), 10) }},
}, { }, {
name: "FastInt-Positive", name: "FastInt-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }},
}, { }, {
name: "FastInt-Negative", name: "FastInt-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }}, test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }},
}} }}
for _, bm := range benchmarks { for _, bm := range benchmarks {
b.Run(bm.name, bm.test) b.Run(bm.name, bm.test)
} }
} }
func BenchmarkFastInt_UintToString(b *testing.B) { type utoaBench struct {
benchmarks := []struct { name string
name string num uint64
test func(*testing.B) }
}{{
name: "StdLib", func BenchmarkFastInt_UintToString(b *testing.B) {
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:], uint64(i), 10) }}, maxUint := "18446744073709551615"
}, { benchs := make([]utoaBench, len(maxUint) + 1)
name: "FastInt", benchs[0].name = "Zero"
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], uint64(i)) }}, benchs[0].num = 0
}} for i := 1; i <= len(maxUint); i++ {
for _, bm := range benchmarks { benchs[i].name = strconv.FormatInt(int64(i), 10) + "-Digs"
b.Run(bm.name, bm.test) benchs[i].num, _ = strconv.ParseUint(string(maxUint[:i]), 10, 64)
} }
}
for _, t := range(benchs) {
benchmarks := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:0], t.num, 10) }},
}, {
name: "FastInt",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], t.num) }},
}}
for _, bm := range benchmarks {
name := fmt.Sprintf("%s_%s", bm.name, t.name)
b.Run(name, bm.test)
}
}
}

View file

@ -39,6 +39,11 @@ func __u64toa(out *byte, val uint64) (ret int)
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int) func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit //go:nosplit
//go:noescape //go:noescape
//goland:noinspection GoUnusedParameter //goland:noinspection GoUnusedParameter

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@ package sse4
var ( var (
S_f64toa = _subr__f64toa S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa S_u64toa = _subr__u64toa
S_lspace = _subr__lspace S_lspace = _subr__lspace

View file

@ -9,28 +9,30 @@ package sse4
func __native_entry__() uintptr func __native_entry__() uintptr
var ( var (
_subr__f32toa = __native_entry__() + 24896
_subr__f64toa = __native_entry__() + 640 _subr__f64toa = __native_entry__() + 640
_subr__html_escape = __native_entry__() + 9808 _subr__html_escape = __native_entry__() + 10672
_subr__i64toa = __native_entry__() + 3440 _subr__i64toa = __native_entry__() + 4304
_subr__lspace = __native_entry__() + 256 _subr__lspace = __native_entry__() + 256
_subr__lzero = __native_entry__() + 16 _subr__lzero = __native_entry__() + 16
_subr__quote = __native_entry__() + 4848 _subr__quote = __native_entry__() + 5712
_subr__skip_array = __native_entry__() + 22320 _subr__skip_array = __native_entry__() + 23184
_subr__skip_number = __native_entry__() + 23824 _subr__skip_number = __native_entry__() + 24688
_subr__skip_object = __native_entry__() + 22368 _subr__skip_object = __native_entry__() + 23232
_subr__skip_one = __native_entry__() + 20448 _subr__skip_one = __native_entry__() + 21312
_subr__u64toa = __native_entry__() + 3568 _subr__u64toa = __native_entry__() + 4432
_subr__unquote = __native_entry__() + 6624 _subr__unquote = __native_entry__() + 7488
_subr__validate_one = __native_entry__() + 23968 _subr__validate_one = __native_entry__() + 24832
_subr__value = __native_entry__() + 13072 _subr__value = __native_entry__() + 13936
_subr__vnumber = __native_entry__() + 18192 _subr__vnumber = __native_entry__() + 19056
_subr__vsigned = __native_entry__() + 19744 _subr__vsigned = __native_entry__() + 20608
_subr__vstring = __native_entry__() + 15152 _subr__vstring = __native_entry__() + 16016
_subr__vunsigned = __native_entry__() + 20096 _subr__vunsigned = __native_entry__() + 20960
) )
const ( const (
_stack__f64toa = 128 _stack__f32toa = 632
_stack__f64toa = 616
_stack__html_escape = 64 _stack__html_escape = 64
_stack__i64toa = 16 _stack__i64toa = 16
_stack__lspace = 8 _stack__lspace = 8
@ -51,6 +53,7 @@ const (
) )
var ( var (
_ = _subr__f32toa
_ = _subr__f64toa _ = _subr__f64toa
_ = _subr__html_escape _ = _subr__html_escape
_ = _subr__i64toa _ = _subr__i64toa
@ -72,6 +75,7 @@ var (
) )
const ( const (
_ = _stack__f32toa
_ = _stack__f64toa _ = _stack__f64toa
_ = _stack__html_escape _ = _stack__html_escape
_ = _stack__i64toa _ = _stack__i64toa

View file

@ -80,7 +80,7 @@ var issue13ExpectedNonemptyOpt = `{
"uint32": 32, "uint32": 32,
"uint64": 64, "uint64": 64,
"float32": 1, "float32": 1,
"float64": -2.34e64, "float64": -2.34e+64,
"uintptr": 1, "uintptr": 1,
"string": "string", "string": "string",
"array": [ "array": [

View file

@ -1,3 +1,19 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package issue_test package issue_test
import ( import (

View file

@ -1,3 +1,19 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package issue_test package issue_test
import ( import (

View file

@ -0,0 +1,40 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package issue_test
import (
`testing`
`encoding/json`
`github.com/bytedance/sonic`
`github.com/stretchr/testify/require`
)
func TestMarshal_Float32To64(t *testing.T) {
var f float32 = 0.1
oe,ee := json.Marshal(f)
os,es := sonic.Marshal(f)
require.Equal(t, ee == nil, es == nil)
require.Equal(t, string(oe), string(os))
var f2,f3 float64
require.Nil(t, json.Unmarshal(oe, &f2))
require.Nil(t, sonic.Unmarshal(os, &f3))
require.Equal(t, f2, f3)
}

View file

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

452
native/f32toa.c Normal file
View file

@ -0,0 +1,452 @@
/* Copyright 2020 Alexander Bolz
*
* Boost Software License - Version 1.0 - August 17th, 2003
*
* Permission is hereby granted, free of charge, to any person or organization
* obtaining a copy of the software and accompanying documentation covered by
* this license (the "Software") to use, reproduce, display, distribute,
* execute, and transmit the Software, and to prepare derivative works of the
* Software, and to permit third-parties to whom the Software is furnished to
* do so, all subject to the following:
*
* The copyright notices in the Software and this entire statement, including
* the above license grant, this restriction and the following disclaimer,
* must be included in all copies of the Software, in whole or in part, and
* all derivative works of the Software, unless such copies or derivative
* works are solely in the form of machine-executable object code generated by
* a source language processor.
*
* Unless required by applicable law or agreed to in writing, this software
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.
*
* This file may have been modified by ByteDance authors. All ByteDance
* Modifications are Copyright 2022 ByteDance Authors.
*/
#include "native.h"
#include "tab.h"
#include "test/xassert.h"
#define F32_BITS 32
#define F32_EXP_BITS 8
#define F32_SIG_BITS 23
#define F32_EXP_MASK 0x7F800000u // middle 8 bits
#define F32_SIG_MASK 0x007FFFFFu // lower 23 bits
#define F32_EXP_BIAS 127
#define F32_INF_NAN_EXP 0xFF
#define F32_HIDDEN_BIT 0x00800000u
typedef struct {
uint32_t sig;
int32_t exp;
} f32_dec;
static inline unsigned ctz10_u32(const uint32_t v) {
xassert(0 <= v && v < 1000000000u);
if (v >= 100000) {
if (v < 1000000) return 6;
if (v < 10000000) return 7;
if (v < 100000000) return 8;
return 9;
} else {
if (v < 10) return 1;
if (v < 100) return 2;
if (v < 1000) return 3;
if (v < 10000) return 4;
return 5;
}
}
static inline char* format_significand_f32(uint32_t sig, char *out, int cnt) {
char *r = out + cnt;
int ctz = 0;
/* at most 9 digits here */
if (sig >= 10000) {
uint32_t c = sig - 10000 * (sig / 10000);
sig /= 10000;
if (c != 0) {
uint32_t c0 = (c % 100) << 1;
uint32_t c1 = (c / 100) << 1;
copy_two_digs(r - 2, Digits + c0);
copy_two_digs(r - 4, Digits + c1);
} else {
ctz = 4;
}
r -= 4;
}
while (sig >= 100) {
uint32_t c = (sig % 100) << 1;
sig /= 100;
copy_two_digs(r - 2, Digits + c);
r -= 2;
}
if (sig >= 10) {
uint32_t c = sig << 1;
copy_two_digs(out, Digits + c);
} else {
*out = (char) ('0' + sig);
}
return out + cnt - ctz;
}
static inline char* format_integer_u32(uint32_t sig, char *out, unsigned cnt) {
char *r = out + cnt;
/* at most 9 digits here */
if (sig >= 10000) {
uint32_t c = sig - 10000 * (sig / 10000);
sig /= 10000;
uint32_t c0 = (c % 100) << 1;
uint32_t c1 = (c / 100) << 1;
copy_two_digs(r - 2, Digits + c0);
copy_two_digs(r - 4, Digits + c1);
r -= 4;
}
while (sig >= 100) {
uint32_t c = (sig % 100) << 1;
sig /= 100;
copy_two_digs(r - 2, Digits + c);
r -= 2;
}
if (sig >= 10) {
uint32_t c = sig << 1;
copy_two_digs(out, Digits + c);
} else {
*out = (char) ('0' + sig);
}
return out + cnt;
}
static inline char* format_exponent_f32(f32_dec v, char *out, int cnt) {
char* p = out + 1;
char* end = format_significand_f32(v.sig, p, cnt);
while (*(end - 1) == '0') end--;
/* Print decimal point if needed */
*out = *p;
if (end - p > 1) {
*p = '.';
} else {
end--;
}
/* Print the exponent */
*end++ = 'e';
int32_t exp = v.exp + (int32_t) cnt - 1;
if (exp < 0) {
*end++ = '-';
exp = -exp;
} else {
*end++ = '+';
}
if (exp >= 100) {
int32_t c = exp % 10;
copy_two_digs(end, Digits + 2 * (exp / 10));
end[2] = (char) ('0' + c);
end += 3;
} else if (exp >= 10) {
copy_two_digs(end, Digits + 2 * exp);
end += 2;
} else {
*end++ = (char) ('0' + exp);
}
return end;
}
static inline char* format_decimal_f32(f32_dec v, char* out, int cnt) {
char* p = out;
char* end;
int point = cnt + v.exp;
/* print leading zeros if fp < 1 */
if (point <= 0) {
*p++ = '0', *p++ = '.';
for (int i = 0; i < -point; i++) {
*p++ = '0';
}
}
/* add the remaining digits */
end = format_significand_f32(v.sig, p, cnt);
while (*(end - 1) == '0') end--;
if (point <= 0) {
return end;
}
/* insert point or add trailing zeros */
int digs = end - p, frac = digs - point;
if (digs > point) {
for (int i = 0; i < frac; i++) {
*(end - i) = *(end - i - 1);
}
p[point] = '.';
end++;
} else {
for (int i = 0; i < point - digs; i++) {
*end++ = '0';
}
}
return end;
}
static inline char* write_dec_f32(f32_dec dec, char* p) {
int cnt = ctz10_u32(dec.sig);
int dot = cnt + dec.exp;
int sci_exp = dot - 1;
bool exp_fmt = sci_exp < -6 || sci_exp > 20;
bool has_dot = dot < cnt;
if (exp_fmt) {
return format_exponent_f32(dec, p, cnt);
}
if (has_dot) {
return format_decimal_f32(dec, p, cnt);
}
char* end = p + dot;
p = format_integer_u32(dec.sig, p, cnt);
while (p < end) *p++ = '0';
return end;
}
static inline uint32_t f32toraw(float fp) {
union {
uint32_t u32;
float f32;
} uval;
uval.f32 = fp;
return uval.u32;
}
static inline uint64_t pow10_ceil_sig_f32(int32_t k)
{
// There are unique beta and r such that 10^k = beta 2^r and
// 2^63 <= beta < 2^64, namely r = floor(log_2 10^k) - 63 and
// beta = 2^-r 10^k.
// Let g = ceil(beta), so (g-1) 2^r < 10^k <= g 2^r, with the latter
// value being a pretty good overestimate for 10^k.
// NB: Since for all the required exponents k, we have g < 2^64,
// all constants can be stored in 128-bit integers.
// reference from:
// https://github.com/abolz/Drachennest/blob/master/src/schubfach_32.cc#L144
#define KMAX 45
#define KMIN -31
static const uint64_t g[KMAX - KMIN + 1] = {
0x81CEB32C4B43FCF5, // -31
0xA2425FF75E14FC32, // -30
0xCAD2F7F5359A3B3F, // -29
0xFD87B5F28300CA0E, // -28
0x9E74D1B791E07E49, // -27
0xC612062576589DDB, // -26
0xF79687AED3EEC552, // -25
0x9ABE14CD44753B53, // -24
0xC16D9A0095928A28, // -23
0xF1C90080BAF72CB2, // -22
0x971DA05074DA7BEF, // -21
0xBCE5086492111AEB, // -20
0xEC1E4A7DB69561A6, // -19
0x9392EE8E921D5D08, // -18
0xB877AA3236A4B44A, // -17
0xE69594BEC44DE15C, // -16
0x901D7CF73AB0ACDA, // -15
0xB424DC35095CD810, // -14
0xE12E13424BB40E14, // -13
0x8CBCCC096F5088CC, // -12
0xAFEBFF0BCB24AAFF, // -11
0xDBE6FECEBDEDD5BF, // -10
0x89705F4136B4A598, // -9
0xABCC77118461CEFD, // -8
0xD6BF94D5E57A42BD, // -7
0x8637BD05AF6C69B6, // -6
0xA7C5AC471B478424, // -5
0xD1B71758E219652C, // -4
0x83126E978D4FDF3C, // -3
0xA3D70A3D70A3D70B, // -2
0xCCCCCCCCCCCCCCCD, // -1
0x8000000000000000, // 0
0xA000000000000000, // 1
0xC800000000000000, // 2
0xFA00000000000000, // 3
0x9C40000000000000, // 4
0xC350000000000000, // 5
0xF424000000000000, // 6
0x9896800000000000, // 7
0xBEBC200000000000, // 8
0xEE6B280000000000, // 9
0x9502F90000000000, // 10
0xBA43B74000000000, // 11
0xE8D4A51000000000, // 12
0x9184E72A00000000, // 13
0xB5E620F480000000, // 14
0xE35FA931A0000000, // 15
0x8E1BC9BF04000000, // 16
0xB1A2BC2EC5000000, // 17
0xDE0B6B3A76400000, // 18
0x8AC7230489E80000, // 19
0xAD78EBC5AC620000, // 20
0xD8D726B7177A8000, // 21
0x878678326EAC9000, // 22
0xA968163F0A57B400, // 23
0xD3C21BCECCEDA100, // 24
0x84595161401484A0, // 25
0xA56FA5B99019A5C8, // 26
0xCECB8F27F4200F3A, // 27
0x813F3978F8940985, // 28
0xA18F07D736B90BE6, // 29
0xC9F2C9CD04674EDF, // 30
0xFC6F7C4045812297, // 31
0x9DC5ADA82B70B59E, // 32
0xC5371912364CE306, // 33
0xF684DF56C3E01BC7, // 34
0x9A130B963A6C115D, // 35
0xC097CE7BC90715B4, // 36
0xF0BDC21ABB48DB21, // 37
0x96769950B50D88F5, // 38
0xBC143FA4E250EB32, // 39
0xEB194F8E1AE525FE, // 40
0x92EFD1B8D0CF37BF, // 41
0xB7ABC627050305AE, // 42
0xE596B7B0C643C71A, // 43
0x8F7E32CE7BEA5C70, // 44
0xB35DBF821AE4F38C, // 45
};
xassert(k >= KMIN && k <= KMAX);
return g[k - KMIN];
#undef KMIN
#undef KMAX
}
static inline uint32_t round_odd_f32(uint64_t g, uint32_t cp) {
const uint128_t p = ((uint128_t)g) * cp;
const uint32_t y1 = (uint64_t)(p >> 64);
const uint32_t y0 = ((uint64_t)(p)) >> 32;
return y1 | (y0 > 1);
}
/**
Rendering float point number into decimal.
The function used Schubfach algorithm, reference:
The Schubfach way to render doubles, Raffaello Giulietti, 2022-03-20.
https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083536.html
https://github.com/openjdk/jdk/pull/3402 (Java implementation)
https://github.com/abolz/Drachennest (C++ implementation)
*/
static inline f32_dec f32todec(uint32_t rsig, int32_t rexp, uint32_t c, int32_t q) {
uint32_t cbl, cb, cbr, vbl, vb, vbr, lower, upper, s;
int32_t k, h;
bool even, irregular, w_inside, u_inside;
f32_dec dec;
even = !(c & 1);
irregular = rsig == 0 && rexp > 1;
cbl = 4 * c - 2 + irregular;
cb = 4 * c;
cbr = 4 * c + 2;
k = (q * 1262611 - (irregular ? 524031 : 0)) >> 22;
h = q + ((-k) * 1741647 >> 19) + 1;
uint64_t pow10 = pow10_ceil_sig_f32(-k);
vbl = round_odd_f32(pow10, cbl << h);
vb = round_odd_f32(pow10, cb << h);
vbr = round_odd_f32(pow10, cbr << h);
lower = vbl + !even;
upper = vbr - !even;
s = vb / 4;
if (s >= 10) {
uint64_t sp = s / 10;
bool up_inside = lower <= (40 * sp);
bool wp_inside = (40 * sp + 40) <= upper;
if (up_inside != wp_inside) {
dec.sig = sp + wp_inside;
dec.exp = k + 1;
return dec;
}
}
u_inside = lower <= (4 * s);
w_inside = (4 * s + 4) <= upper;
if (u_inside != w_inside) {
dec.sig = s + w_inside;
dec.exp = k;
return dec;
}
uint64_t mid = 4 * s + 2;
bool round_up = vb > mid || (vb == mid && (s & 1) != 0);
dec.sig = s + round_up;
dec.exp = k;
return dec;
}
int f32toa(char *out, float fp) {
char* p = out;
uint32_t raw = f32toraw(fp);
bool neg;
uint32_t rsig, c;
int32_t rexp, q;
neg = ((raw >> (F32_BITS - 1)) != 0);
rsig = raw & F32_SIG_MASK;
rexp = (int32_t)((raw & F32_EXP_MASK) >> F32_SIG_BITS);
/* check infinity and nan */
if (unlikely(rexp == F32_INF_NAN_EXP)) {
return 0;
}
/* check negative numbers */
*p = '-';
p += neg;
/* simple case of 0.0 */
if ((raw << 1) == 0) {
*p++ = '0';
return p - out;
}
if (likely(rexp != 0)) {
/* double is normal */
c = rsig | F32_HIDDEN_BIT;
q = rexp - F32_EXP_BIAS - F32_SIG_BITS;
/* fast path for integer */
if (q <= 0 && q >= -F32_SIG_BITS && is_div_pow2(c, -q)) {
uint32_t u = c >> -q;
p = format_integer_u32(u, p, ctz10_u32(u));
return p - out;
}
} else {
c = rsig;
q = 1 - F32_EXP_BIAS - F32_SIG_BITS;
}
f32_dec dec = f32todec(rsig, rexp, c, q);
p = write_dec_f32(dec, p);
return p - out;
}
#undef F32_BITS
#undef F32_EXP_BITS
#undef F32_SIG_BITS
#undef F32_EXP_MASK
#undef F32_SIG_MASK
#undef F32_EXP_BIAS
#undef F32_INF_NAN_EXP
#undef F32_HIDDEN_BIT

View file

@ -1,485 +1,405 @@
/* Copyright 2018 Ulf Adams. /* Copyright 2020 Alexander Bolz
* Modifications copyright 2021 ByteDance Inc. *
* * Boost Software License - Version 1.0 - August 17th, 2003
* The contents of this file may be used under the terms of the Apache License, *
* Version 2.0. * Permission is hereby granted, free of charge, to any person or organization
* * obtaining a copy of the software and accompanying documentation covered by
* (See accompanying file LICENSE-Apache or copy at * this license (the "Software") to use, reproduce, display, distribute,
* http: *www.apache.org/licenses/LICENSE-2.0) * execute, and transmit the Software, and to prepare derivative works of the
* * Software, and to permit third-parties to whom the Software is furnished to
* Alternatively, the contents of this file may be used under the terms of * do so, all subject to the following:
* the Boost Software License, Version 1.0. *
* (See accompanying file LICENSE-Boost or copy at * The copyright notices in the Software and this entire statement, including
* https: *www.boost.org/LICENSE_1_0.txt) * the above license grant, this restriction and the following disclaimer,
* must be included in all copies of the Software, in whole or in part, and
* all derivative works of the Software, unless such copies or derivative
* works are solely in the form of machine-executable object code generated by
* a source language processor.
* *
* Unless required by applicable law or agreed to in writing, this software * Unless required by applicable law or agreed to in writing, this software
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. * KIND, either express or implied.
*
* This file may have been modified by ByteDance authors. All ByteDance
* Modifications are Copyright 2022 ByteDance Authors.
*/ */
#include "native.h"
#include "ryu_tab.h"
/* use 128-bit type for performance */ #include "native.h"
#include "tab.h"
#include "test/xassert.h"
#define F64_BITS 64
#define F64_EXP_BITS 11
#define F64_SIG_BITS 52
#define F64_EXP_MASK 0x7FF0000000000000ull // middle 11 bits
#define F64_SIG_MASK 0x000FFFFFFFFFFFFFull // lower 52 bits
#define F64_EXP_BIAS 1023
#define F64_INF_NAN_EXP 0x7FF
#define F64_HIDDEN_BIT 0x0010000000000000ull
struct f64_dec {
uint64_t sig;
int64_t exp;
};
typedef struct f64_dec f64_dec;
typedef __uint128_t uint128_t; typedef __uint128_t uint128_t;
/* Returns e == 0 ? 1 : ceil(log_2(5^e)) */ static inline unsigned ctz10(const uint64_t v) {
static inline int32_t pow5bits(const int32_t e) { xassert(0 <= v && v < 100000000000000000ull);
return (int32_t) (((((uint32_t) e) * 1217359) >> 19) + 1); if (v >= 10000000000ull) {
} if (v < 100000000000ull) return 11;
if (v < 1000000000000ull) return 12;
/* Returns floor(log_10(2^e)) */ if (v < 10000000000000ull) return 13;
static inline uint32_t log10pow2(const int32_t e) { if (v < 100000000000000ull) return 14;
return (((uint32_t) e) * 78913) >> 18; if (v < 1000000000000000ull) return 15;
} if (v < 10000000000000000ull) return 16;
return 17;
/* Returns floor(log_10(5^e)) */
static inline uint32_t log10pow5(const int32_t e) {
return (((uint32_t) e) * 732923) >> 20;
}
static inline uint32_t pow5factor(uint64_t v) {
uint64_t m_inv5 = 14757395258967641293u; // *5 = 1(mod 2^64)
uint64_t n_div5 = 3689348814741910323u; // =2^64 / 5
uint32_t cnt = 0;
for (;;) {
v *= m_inv5;
if (v > n_div5)
break;
++cnt;
} }
return cnt; if (v < 10ull) return 1;
if (v < 100ull) return 2;
if (v < 1000ull) return 3;
if (v < 10000ull) return 4;
if (v < 100000ull) return 5;
if (v < 1000000ull) return 6;
if (v < 10000000ull) return 7;
if (v < 100000000ull) return 8;
if (v < 1000000000ull) return 9;
return 10;
} }
/* Returns true if value is divisible by 5^p */ static inline char* format_significand(uint64_t sig, char *out, int cnt) {
static inline bool ispow5(const uint64_t v, const uint32_t p) { char *p = out + cnt;
return pow5factor(v) >= p; int ctz = 0;
}
/* Returns true if value is divisible by 2^p */ if ((sig >> 32) != 0) {
static inline bool ispow2(const uint64_t v, const uint32_t p) { uint64_t q = sig / 100000000;
return (v & ((1ull << p) - 1)) == 0; uint32_t r = ((uint32_t)sig) - 100000000 * ((uint32_t) q);
} sig = q;
if (r != 0) {
uint32_t c = r % 10000;
r /= 10000;
uint32_t d = r % 10000;
uint32_t c0 = (c % 100) << 1;
uint32_t c1 = (c / 100) << 1;
uint32_t d0 = (d % 100) << 1;
uint32_t d1 = (d / 100) << 1;
copy_two_digs(p - 2, Digits + c0);
copy_two_digs(p - 4, Digits + c1);
copy_two_digs(p - 6, Digits + d0);
copy_two_digs(p - 8, Digits + d1);
} else {
ctz += 8;
}
p -= 8;
}
/* Requires 0 <= v < v < 100000000000000000L */ uint32_t sig2 = (uint32_t)sig;
static inline uint32_t ctz10(const uint64_t v) { while (sig2 >= 10000) {
if (v < 10) return 1; uint32_t c = sig2 - 10000 * (sig2 / 10000);
if (v < 100) return 2; sig2 /= 10000;
if (v < 1000) return 3; uint32_t c0 = (c % 100) << 1;
if (v < 10000) return 4; uint32_t c1 = (c / 100) << 1;
if (v < 100000) return 5; copy_two_digs(p - 2, Digits + c0);
if (v < 1000000) return 6; copy_two_digs(p - 4, Digits + c1);
if (v < 10000000) return 7; p -= 4;
if (v < 100000000) return 8; }
if (v < 1000000000) return 9; if (sig2 >= 100) {
if (v < 10000000000) return 10; uint32_t c = (sig2 % 100) << 1;
if (v < 100000000000) return 11; sig2 /= 100;
if (v < 1000000000000) return 12; copy_two_digs(p - 2, Digits + c);
if (v < 10000000000000) return 13; p -= 2;
if (v < 100000000000000) return 14; }
if (v < 1000000000000000) return 15; if (sig2 >= 10) {
if (v < 10000000000000000) return 16; uint32_t c = sig2 << 1;
return 17; copy_two_digs(p - 2, Digits + c);
}
/* Best case: use 128-bit type */
static inline uint64_t mulshift(const uint64_t m, const uint64_t *mul, const int32_t j) {
uint128_t lo = ((uint128_t) m) * mul[0];
uint128_t hi = ((uint128_t) m) * mul[1];
return (uint64_t) (((lo >> 64) + hi) >> (j - 64));
}
#define mul_shift_all(m, mul, j, shift) \
vp = mulshift(4 * m + 2, mul, j); \
vm = mulshift(4 * m - 1 - shift, mul, j); \
vr = mulshift(4 * m, mul, j);
#define copy_two_digs(dst, src) \
*(dst) = *(src); \
*(dst+1) = *(src+1);
/* A floating decimal representing man * 10^exp */
typedef struct f64_d {
uint64_t man;
int32_t exp;
} f64_d;
static inline f64_d f64tod(const uint64_t man,const uint32_t exp) {
int32_t e2;
uint64_t m2;
if (exp == 0) {
/* subtract 2 so that the bounds computation has 2 additional bits */
e2 = 1 - 1023 - 52 - 2;
m2 = man;
} else { } else {
e2 = (int32_t) exp - 1023 - 52 - 2; *out = (char) ('0' + sig2);
m2 = (1ull << 52) | man;
} }
bool even = (m2 & 1) == 0; return out + cnt - ctz;
/* Step 2: Determine the interval of valid decimal representations */
uint64_t mv = 4 * m2;
/* Implicit bool -> int conversion. True is 1, false is 0 */
uint32_t shift = man != 0 || exp <= 1;
/* Step 3: Convert to a decimal power base using 128-bit arithmetic */
uint64_t vr, vp, vm;
int32_t e10;
bool vmzeros = false;
bool vrzeros = false;
if (e2 >= 0) {
uint32_t q = log10pow2(e2) - (e2 > 3); // max(0, log10pow2(e2) - 1)
e10 = (int32_t) q;
int32_t k = DOUBLE_POW5_INV_BITCOUNT + pow5bits((int32_t) q) - 1;
int32_t i = -e2 + (int32_t) q + k;
uint64_t *mul = (uint64_t*)DOUBLE_POW5_INV_SPLIT[q];
/* {vm, vr, vp} * 10^e10 = {mm, mv, mp} * 2^e2
* mp = 4 * m2 + 2
* mm = mv - 1 - shift
*/
mul_shift_all(m2, mul, i, shift)
if (q <= 21) {
if (mv % 5 == 0) {
vrzeros = ispow5(mv, q);
} else if (even) {
/* Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q
* <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q
* <=> true && pow5Factor(mm) >= q, since e2 >= q.
*/
vmzeros = ispow5(mv - 1 - shift, q);
} else {
/* Same as min(e2 + 1, pow5Factor(mp)) >= q. */
vp -= ispow5(mv + 2, q);
}
}
} else {
uint32_t q = log10pow5(-e2) - (-e2 > 1); // max(0, log10pow5(-e2) - 1)
e10 = (int32_t) q + e2;
int32_t i = -e2 - (int32_t) q;
int32_t k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
int32_t j = (int32_t) q - k;
uint64_t *mul = (uint64_t*)DOUBLE_POW5_SPLIT[i];
/* {vm, vr, vp} * 10^e10 = {mm, mv, mp} * 2^e2 */
mul_shift_all(m2, mul, j, shift)
if (q <= 1) {
/* {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing
* 0 bits. mv = 4 * m2, so it always has at least two trailing 0 bits.
*/
vrzeros = true;
if (even) {
/* mm = mv - 1 - shift, so it has 1 trailing 0 bit if shift = 1 */
vmzeros = shift == 1;
} else {
/* mp = mv + 2, so it always has at least one trailing 0 bit */
--vp;
}
} else if (q < 63) {
vrzeros = ispow2(mv, q);
}
}
/* Step 4: Find the shortest decimal representation in the interval */
int32_t removed = 0;
uint8_t lastrmdig = 0;
uint64_t dman;
/* On average, we remove ~2 DIGs */
if (vmzeros || vrzeros) {
/* General case, which happens rarely (~0.7%) */
for (;;) {
uint64_t vpdiv10 = vp / 10;
uint64_t vmdiv10 = vm / 10;
if (vpdiv10 <= vmdiv10) {
break;
}
uint32_t vmmod10 = ((uint32_t) vm) - 10 * ((uint32_t) vmdiv10);
uint64_t vrdiv10 = vr / 10;
uint32_t vrmod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrdiv10);
vmzeros &= vmmod10 == 0;
vrzeros &= lastrmdig == 0;
lastrmdig = (uint8_t) vrmod10;
vr = vrdiv10;
vp = vpdiv10;
vm = vmdiv10;
++removed;
}
if (vmzeros) {
for (;;) {
uint64_t vmdiv10 = vm / 10;
uint32_t vmmod10 = ((uint32_t) vm) - 10 * ((uint32_t) vmdiv10);
if (vmmod10 != 0) {
break;
}
uint64_t vpdiv10 = vp / 10;
uint64_t vrdiv10 = vr / 10;
uint32_t vrmod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrdiv10);
vrzeros &= lastrmdig == 0;
lastrmdig = (uint8_t) vrmod10;
vr = vrdiv10;
vp = vpdiv10;
vm = vmdiv10;
++removed;
}
}
if (vrzeros && lastrmdig == 5 && vr % 2 == 0) {
/* Round even if the exact number is .....50..0 */
lastrmdig = 4;
}
/* We need to take vr + 1 if vr is outside bounds or we need to round up */
dman = vr + ((vr == vm && (!even || !vmzeros)) || lastrmdig >= 5);
} else {
/* Specialized for the common case (~99.3%). Percentages below are relative to this */
bool roundup= false;
uint64_t vpdiv100 = vp / 100;
uint64_t vmdiv100 = vm / 100;
if (vpdiv100 > vmdiv100) { // Optimization: remove two DIGs at a time (~86.2%).
uint64_t vrdiv100 = vr / 100;
uint32_t vrmod100 = ((uint32_t) vr) - 100 * ((uint32_t) vrdiv100);
roundup = vrmod100 >= 50;
vr = vrdiv100;
vp = vpdiv100;
vm = vmdiv100;
removed += 2;
}
/* Loop iterations below (approximately), without optimization above:
* 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
* Loop iterations below (approximately), with optimization above:
* 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
*/
for (;;) {
uint64_t vpdiv10 = vp / 10;
uint64_t vmdiv10 = vm / 10;
if (vpdiv10 <= vmdiv10) {
break;
}
uint64_t vrdiv10 = vr / 10;
uint32_t vrmod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrdiv10);
roundup = vrmod10 >= 5;
vr = vrdiv10;
vp = vpdiv10;
vm = vmdiv10;
++removed;
}
/* We need to take vr + 1 if vr is outside bounds or we need to round up */
dman = vr + (vr == vm || roundup);
}
f64_d fd = {
.exp = e10 + removed,
.man = dman,
};
return fd;
} }
/* Print the decimal DIGs from mantissa */ static inline char* format_integer(uint64_t sig, char *out, unsigned cnt) {
static inline void print_mantissa(uint64_t man, char *out, int mlen) { char *p = out + cnt;
/* We have at most 17 DIGs, and uint32_t can store 9 DIGs. if ((sig >> 32) != 0) {
* If man doesn't fit into uint32_t, we cut off 8 DIGs, uint64_t q = sig / 100000000;
* so the rest will fit into uint32_t. uint32_t r = ((uint32_t)sig) - 100000000 * ((uint32_t) q);
*/ sig = q;
char *r = out + mlen; uint32_t c = r % 10000;
if (man < 10) {} r /= 10000;
if ((man >> 32) != 0) { uint32_t d = r % 10000;
/* Expensive 64-bit division */
uint64_t q = man / 100000000;
uint32_t man2 = ((uint32_t) man) - 100000000 * ((uint32_t) q);
man = q;
uint32_t c = man2 % 10000;
man2 /= 10000;
uint32_t d = man2 % 10000;
uint32_t c0 = (c % 100) << 1; uint32_t c0 = (c % 100) << 1;
uint32_t c1 = (c / 100) << 1; uint32_t c1 = (c / 100) << 1;
uint32_t d0 = (d % 100) << 1; uint32_t d0 = (d % 100) << 1;
uint32_t d1 = (d / 100) << 1; uint32_t d1 = (d / 100) << 1;
copy_two_digs(r - 2, DIG_TAB + c0) copy_two_digs(p - 2, Digits + c0);
copy_two_digs(r - 4, DIG_TAB + c1) copy_two_digs(p - 4, Digits + c1);
copy_two_digs(r - 6, DIG_TAB + d0) copy_two_digs(p - 6, Digits + d0);
copy_two_digs(r - 8, DIG_TAB + d1) copy_two_digs(p - 8, Digits + d1);
r -= 8; p -= 8;
} }
uint32_t man2 = (uint32_t) man;
while (man2 >= 10000) { uint32_t sig2 = (uint32_t)sig;
#ifdef __clang__ // https://bugs.llvm.org/show_bug.cgi?id=38217 while (sig2 >= 10000) {
uint32_t c = man2 - 10000 * (man2 / 10000); uint32_t c = sig2 - 10000 * (sig2 / 10000);
#else sig2 /= 10000;
uint32_t c = man2 % 10000;
#endif
man2 /= 10000;
uint32_t c0 = (c % 100) << 1; uint32_t c0 = (c % 100) << 1;
uint32_t c1 = (c / 100) << 1; uint32_t c1 = (c / 100) << 1;
copy_two_digs(r - 2, DIG_TAB + c0) copy_two_digs(p - 2, Digits + c0);
copy_two_digs(r - 4, DIG_TAB + c1) copy_two_digs(p - 4, Digits + c1);
r -= 4; p -= 4;
} }
if (man2 >= 100) { if (sig2 >= 100) {
uint32_t c = (man2 % 100) << 1; uint32_t c = (sig2 % 100) << 1;
man2 /= 100; sig2 /= 100;
copy_two_digs(r - 2, DIG_TAB + c) copy_two_digs(p - 2, Digits + c);
r -= 2; p -= 2;
} }
if (man2 >= 10) { if (sig2 >= 10) {
uint32_t c = man2 << 1; uint32_t c = sig2 << 1;
copy_two_digs(r - 2, DIG_TAB + c) copy_two_digs(p - 2, Digits + c);
} else { } else {
*out = (char) ('0' + man2); *out = (char) ('0' + sig2);
} }
return out + cnt;
} }
static inline int print_exponent(f64_d v, char *out, int mlen) { static inline char* format_exponent(f64_dec v, char *out, unsigned cnt) {
int idx = 0; char* p = out + 1;
char* end = format_significand(v.sig, p, cnt);
while (*(end - 1) == '0') end--;
print_mantissa(v.man, out + idx + 1, mlen); /* print decimal point if needed */
*out = *p;
/* Print decimal point if needed */ if (end - p > 1) {
out[idx] = out[idx + 1]; *p = '.';
if (mlen > 1) {
out[idx + 1] = '.';
idx += mlen + 1;
} else { } else {
++idx; end--;
} }
/* Print the exponent */ /* print the exponent */
out[idx++] = 'e'; *end++ = 'e';
int32_t exp = v.exp + (int32_t) mlen - 1; int32_t exp = v.exp + (int32_t) cnt - 1;
if (exp < 0) { if (exp < 0) {
out[idx++] = '-'; *end++ = '-';
exp = -exp; exp = -exp;
} else {
*end++ = '+';
} }
if (exp >= 100) { if (exp >= 100) {
int32_t c = exp % 10; int32_t c = exp % 10;
copy_two_digs(out + idx, DIG_TAB + 2 * (exp / 10)) copy_two_digs(end, Digits + 2 * (exp / 10));
out[idx + 2] = (char) ('0' + c); end[2] = (char) ('0' + c);
idx += 3; end += 3;
} else if (exp >= 10) { } else if (exp >= 10) {
copy_two_digs(out + idx, DIG_TAB + 2 * exp) copy_two_digs(end, Digits + 2 * exp);
idx += 2; end += 2;
} else { } else {
out[idx++] = (char) ('0' + exp); *end++ = (char) ('0' + exp);
} }
return end;
return idx;
} }
static inline int print_decimal(const f64_d v, char *out, int mlen) { static inline char* format_decimal(f64_dec v, char* out, unsigned cnt) {
int idx = 0; char* p = out;
int lzeros = 0; char* end;
int rzeros = 0; int point = cnt + v.exp;
int point = 0;
int exp10 = mlen - 1 + v.exp;
/* parse the point idx and additional zeros */ /* print leading zeros if fp < 1 */
if (exp10 < 0) { if (point <= 0) {
lzeros = -exp10; *p++ = '0', *p++ = '.';
point = 1; for (int i = 0; i < -point; i++) {
} else if (exp10 < mlen - 1) { *p++ = '0';
point = 1 + exp10;
} else {
rzeros = exp10 - mlen + 1;
}
int i = 0;
/* add left zeros */
if (lzeros) {
out[idx++] = '0';
out[idx++] = '.';
point = 0;
}
for (i = 1; i < lzeros; ++i) {
out[idx++] = '0';
}
/* add the mantissa DIGs */
print_mantissa(v.man, out + idx, mlen);
if (point) {
for (i = idx + mlen; i > idx + point; --i) {
out[i] = out[i-1];
} }
out[idx + point] = '.';
idx += 1;
} }
/* add right zeros */ /* add the remaining digits */
idx += mlen; end = format_significand(v.sig, p, cnt);
for (i = 0; i < rzeros; ++i) { while (*(end - 1) == '0') end--;
out[idx++] = '0'; if (point <= 0) {
return end;
} }
return idx; /* insert point or add trailing zeros */
int digs = end - p;
if (digs > point) {
for (int i = 0; i < digs - point; i++) {
*(end - i) = *(end - i - 1);
}
p[point] = '.';
end++;
} else {
for (int i = 0; i < point - digs; i++) {
*end++ = '0';
}
}
return end;
} }
static inline bool f64tod_exct_int(const uint64_t man, const uint32_t exp, static inline char* write_dec(f64_dec dec, char* p) {
f64_d* v) { int cnt = ctz10(dec.sig);
uint64_t m2 = (1ull << 52) | man; // implicit 1 int dot = cnt + dec.exp;
int32_t e2 = (int32_t) exp - 1023 - 52; int sci_exp = dot - 1;
bool exp_fmt = sci_exp < -6 || sci_exp > 20;
bool has_dot = dot < cnt;
if (e2 > 0 || e2 < -52) { if (exp_fmt) {
return false; return format_exponent(dec, p, cnt);
}
if (has_dot) {
return format_decimal(dec, p, cnt);
} }
uint64_t mask = (1ull << -e2) - 1; char* end = p + dot;
if ((m2 & mask) != 0) { // with fraction p = format_integer(dec.sig, p, cnt);
return false; while (p < end) *p++ = '0';
} return end;
v->man = m2 >> -e2;
v->exp = 0;
return true;
} }
static int inline ryu(uint64_t bits, char *out) { static inline uint64_t f64toraw(double fp) {
/* Step 1: Decode the floating-point number */ union {
uint64_t man = bits & ((1ull << 52) - 1); uint64_t u64;
uint32_t exp = (uint32_t) ((bits >> 52) & ((1u << 11) - 1)); double f64;
} uval;
uval.f64 = fp;
return uval.u64;
}
/* Skip when Infinity */ static inline uint64_t round_odd(uint64x2 g, uint64_t cp) {
if (exp == ((1u << 11) - 1u)) { const uint128_t x = ((uint128_t)cp) * g.lo;
const uint128_t y = ((uint128_t)cp) * g.hi + ((uint64_t)(x >> 64));
const uint64_t y0 = ((uint64_t)y);
const uint64_t y1 = ((uint64_t)(y >> 64));
return y1 | (y0 > 1);
}
/**
Rendering float point number into decimal.
The function used Schubfach algorithm, reference:
The Schubfach way to render doubles, Raffaello Giulietti, 2022-03-20.
https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083536.html
https://github.com/openjdk/jdk/pull/3402 (Java implementation)
https://github.com/abolz/Drachennest (C++ implementation)
*/
static inline f64_dec f64todec(uint64_t rsig, int32_t rexp, uint64_t c, int32_t q) {
uint64_t cbl, cb, cbr, vbl, vb, vbr, lower, upper, s;
int32_t k, h;
bool even, irregular, w_inside, u_inside;
f64_dec dec;
even = !(c & 1);
irregular = rsig == 0 && rexp > 1;
cbl = 4 * c - 2 + irregular;
cb = 4 * c;
cbr = 4 * c + 2;
/* q is in [-1500, 1500]
k = irregular ? floor(log_10(3/4 * 2^q)) : floor(log10(pow(2^q)))
floor(log10(3/4 * 2^q)) = (q * 1262611 - 524031) >> 22
floor(log10(pow(2^q))) = (q * 1262611) >> 22 */
k = (q * 1262611 - (irregular ? 524031 : 0)) >> 22;
/* k is in [-1233, 1233]
s = floor(V) = floor(c * 2^q * 10^-k)
vb = 4V = 4 * c * 2^q * 10^-k */
h = q + ((-k) * 1741647 >> 19) + 1;
uint64x2 pow10 = pow10_ceil_sig(-k);
vbl = round_odd(pow10, cbl << h);
vb = round_odd(pow10, cb << h);
vbr = round_odd(pow10, cbr << h);
lower = vbl + !even;
upper = vbr - !even;
s = vb / 4;
if (s >= 10) {
/* R_k+1 interval contains at most one: up or wp */
uint64_t sp = s / 10;
bool up_inside = lower <= (40 * sp);
bool wp_inside = (40 * sp + 40) <= upper;
if (up_inside != wp_inside) {
dec.sig = sp + wp_inside;
dec.exp = k + 1;
return dec;
}
}
/* R_k interval contains at least one: u or w */
u_inside = lower <= (4 * s);
w_inside = (4 * s + 4) <= upper;
if (u_inside != w_inside) {
dec.sig = s + w_inside;
dec.exp = k;
return dec;
}
/* R_k interval contains both u or w */
uint64_t mid = 4 * s + 2;
bool round_up = vb > mid || (vb == mid && (s & 1) != 0);
dec.sig = s + round_up;
dec.exp = k;
return dec;
}
int f64toa(char *out, double fp) {
char* p = out;
uint64_t raw = f64toraw(fp);
bool neg;
uint64_t rsig, c;
int32_t rexp, q;
neg = ((raw >> (F64_BITS - 1)) != 0);
rsig = raw & F64_SIG_MASK;
rexp = (int32_t)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
/* check infinity and nan */
if (unlikely(rexp == F64_INF_NAN_EXP)) {
return 0; return 0;
} }
f64_d v; /* check negative numbers */
/* for integer from [1, 2^53], can be resepensated exactly by double */ *p = '-';
bool is_exact_int = f64tod_exct_int(man, exp, &v); p += neg;
if (!is_exact_int){ // find the shortest decimal representation
v = f64tod(man, exp);
}
/* Step 5: Print the decimal representation */
int idx = 0;
uint32_t mlen = ctz10(v.man);
int exp10 = mlen - 1 + v.exp;
/* The format as Go encoding/json package */
bool isexp = exp10 < -6 || exp10 >= 21;
if (isexp) // exponent format
idx += print_exponent(v, out + idx, mlen);
else // decimal format
idx += print_decimal(v, out + idx, mlen);
return idx;
}
int f64toa(char *out, double val) {
int i = 0;
char *p = out;
uint64_t uval = *(uint64_t *)&val;
/* negative numbers */
if (unlikely(uval >> 63) == 1) {
i = 1;
uval &= ((1ull << 63) - 1);
*p++ = '-';
}
/* simple case of 0.0 */ /* simple case of 0.0 */
if (uval == 0) { if ((raw << 1) == 0) {
*p = '0'; *p++ = '0';
return i + 1; return p - out;
} }
/* print the number with Ryu algorithm */ /* fp = c * 2^q */
int n = ryu(uval, p); if (likely(rexp != 0)) {
return n + i; /* double is normal */
c = rsig | F64_HIDDEN_BIT;
q = rexp - F64_EXP_BIAS - F64_SIG_BITS;
/* fast path for integer */
if (q <= 0 && q >= -F64_SIG_BITS && is_div_pow2(c, -q)) {
uint64_t u = c >> -q;
p = format_integer(u, p, ctz10(u));
return p - out;
}
} else {
c = rsig;
q = 1 - F64_EXP_BIAS - F64_SIG_BITS;
}
f64_dec dec = f64todec(rsig, rexp, c, q);
p = write_dec(dec, p);
return p - out;
} }
#undef F64_BITS
#undef F64_EXP_BITS
#undef F64_SIG_BITS
#undef F64_EXP_MASK
#undef F64_SIG_MASK
#undef F64_EXP_BIAS
#undef F64_INF_NAN_EXP
#undef F64_HIDDEN_BIT

View file

@ -15,19 +15,7 @@
*/ */
#include "native.h" #include "native.h"
#include "tab.h"
static const char Digits[200] = {
'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',
};
static const char Vec16xA0[16] __attribute__((aligned(16))) = { static const char Vec16xA0[16] __attribute__((aligned(16))) = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',

View file

@ -20,4 +20,5 @@
#include "parsing.c" #include "parsing.c"
#include "atof_eisel_lemire.c" #include "atof_eisel_lemire.c"
#include "atof_native.c" #include "atof_native.c"
#include "scanning.c" #include "scanning.c"
#include "f32toa.c"

View file

@ -268,10 +268,8 @@ static inline uint8_t escape_mask4(const char *sp) {
static inline ssize_t memcchr_quote_unsafe(const char *sp, ssize_t nb, char *dp, const quoted_t * tab) { static inline ssize_t memcchr_quote_unsafe(const char *sp, ssize_t nb, char *dp, const quoted_t * tab) {
uint32_t mm; uint32_t mm;
const char * ss = sp;
const char * ds = dp; const char * ds = dp;
size_t cn = 0; size_t cn = 0;
uint8_t ch;
simd_copy: simd_copy:

View file

@ -1,385 +0,0 @@
/* Copyright 2018 Ulf Adams.
* Modifications copyright 2021 ByteDance Inc.
*
* The contents of this file may be used under the terms of the Apache License,
* Version 2.0.
*
* (See accompanying file LICENSE-Apache or copy at
* http: *www.apache.org/licenses/LICENSE-2.0)
*
* Alternatively, the contents of this file may be used under the terms of
* the Boost Software License, Version 1.0.
* (See accompanying file LICENSE-Boost or copy at
* https: *www.boost.org/LICENSE_1_0.txt)
*
* Unless required by applicable law or agreed to in writing, this software
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.
*/
#ifndef RYU_TAB_H
#define RYU_TAB_H
/* These tables are generated by PrintDoubleLookupTable */
#define DOUBLE_POW5_INV_BITCOUNT 125
#define DOUBLE_POW5_BITCOUNT 125
#define DOUBLE_POW5_INV_TABLE_SIZE 342
#define DOUBLE_POW5_TABLE_SIZE 326
/* A table of all two-digit numbers. This is used to speed up decimal digit
* generation by copying pairs of digits into the final output.
*/
static const char DIG_TAB[200] = {
'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'
};
static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = {
{ 1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u },
{ 5165088340638674453u, 1475739525896764129u }, { 7821419487252849886u, 1180591620717411303u },
{ 8824922364862649494u, 1888946593147858085u }, { 7059937891890119595u, 1511157274518286468u },
{ 13026647942995916322u, 1208925819614629174u }, { 9774590264567735146u, 1934281311383406679u },
{ 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u },
{ 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u },
{ 9162556910162266299u, 1267650600228229401u }, { 7281393426775805432u, 2028240960365167042u },
{ 16893161185646375315u, 1622592768292133633u }, { 2446482504291369283u, 1298074214633706907u },
{ 7603720821608101175u, 2076918743413931051u }, { 2393627842544570617u, 1661534994731144841u },
{ 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u },
{ 5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u },
{ 3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u },
{ 6382248639981364905u, 1393796574908163946u }, { 2832900194486363201u, 2230074519853062314u },
{ 5955668970331000884u, 1784059615882449851u }, { 1075186361522890384u, 1427247692705959881u },
{ 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u },
{ 3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u },
{ 5547241898389809503u, 1870722095783555735u }, { 4437793518711847602u, 1496577676626844588u },
{ 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u },
{ 6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u },
{ 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u },
{ 14151565162110759939u, 1255420347077336152u }, { 7885109000409574610u, 2008672555323737844u },
{ 9997436015069570011u, 1606938044258990275u }, { 7997948812055656009u, 1285550435407192220u },
{ 12796718099289049614u, 2056880696651507552u }, { 2858676849947419045u, 1645504557321206042u },
{ 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u },
{ 3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u },
{ 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u },
{ 8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u },
{ 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u },
{ 15986332124095098083u, 2261564242916331941u }, { 9099716884534168143u, 1809251394333065553u },
{ 14658471137111155161u, 1447401115466452442u }, { 4348079280205103483u, 1157920892373161954u },
{ 14335624477811986218u, 1852673427797059126u }, { 7779150767507678651u, 1482138742237647301u },
{ 2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u },
{ 12097921058438802501u, 1517710072051350836u }, { 5988988032009131678u, 1214168057641080669u },
{ 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u },
{ 7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u },
{ 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u },
{ 4951948911778577463u, 2037035976334486086u }, { 272210314680951647u, 1629628781067588869u },
{ 3907117066486671641u, 1303703024854071095u }, { 6251387306378674625u, 2085924839766513752u },
{ 16069156289328670670u, 1668739871813211001u }, { 9165976216721026213u, 1334991897450568801u },
{ 7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u },
{ 13518030318433270404u, 1367031702989382452u }, { 6871453250525591353u, 2187250724783011924u },
{ 9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u },
{ 10282995085511086630u, 2239744742177804210u }, { 8226396068408869304u, 1791795793742243368u },
{ 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u },
{ 5324776569667477496u, 1834798892792057209u }, { 7949170070475892320u, 1467839114233645767u },
{ 17427382500606444826u, 1174271291386916613u }, { 5747719112518849781u, 1878834066219066582u },
{ 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u },
{ 5295368560860596524u, 1923926083808324180u }, { 4236294848688477220u, 1539140867046659344u },
{ 7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u },
{ 9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u },
{ 12335095245094488799u, 2017382717255397335u }, { 9868076196075591040u, 1613906173804317868u },
{ 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u },
{ 7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u },
{ 11918976037903224966u, 2115379100128795516u }, { 5845832015580669650u, 1692303280103036413u },
{ 12055363241948356366u, 1353842624082429130u }, { 841837113407818570u, 2166148198531886609u },
{ 4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u },
{ 12225235553534690011u, 2218135755296651887u }, { 2401490813343931363u, 1774508604237321510u },
{ 1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u },
{ 6886345170554478103u, 1817096810739017226u }, { 1819727321701672159u, 1453677448591213781u },
{ 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u },
{ 15587778368262418694u, 1488565707357402911u }, { 8780873879868024632u, 1190852565885922329u },
{ 2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u },
{ 7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u },
{ 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u },
{ 1553625868034358140u, 1997919072202235028u }, { 8621598323911307159u, 1598335257761788022u },
{ 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u },
{ 121653480894270168u, 1636695303948070935u }, { 97322784715416134u, 1309356243158456748u },
{ 14913111714512307107u, 2094969989053530796u }, { 8241140556867935363u, 1675975991242824637u },
{ 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u },
{ 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u },
{ 14650556434236701088u, 2196735251241795108u }, { 652398703163629901u, 1757388200993436087u },
{ 11589965406756634890u, 1405910560794748869u }, { 7475898206584884855u, 2249456897271598191u },
{ 2291369750525997561u, 1799565517817278553u }, { 9211793429904618695u, 1439652414253822842u },
{ 18428218302589300235u, 2303443862806116547u }, { 7363877012587619542u, 1842755090244893238u },
{ 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u },
{ 2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u },
{ 13231802778477390823u, 1207667975942893232u }, { 6413489186596184024u, 1932268761508629172u },
{ 16198837793502678189u, 1545815009206903337u }, { 5580372605318321905u, 1236652007365522670u },
{ 8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u },
{ 7190041073742725760u, 1266331655542295214u }, { 436019273762630246u, 2026130648867672343u },
{ 7727513048493924843u, 1620904519094137874u }, { 9871359253537050198u, 1296723615275310299u },
{ 4726128361433549347u, 2074757784440496479u }, { 7470251503888749801u, 1659806227552397183u },
{ 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u },
{ 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u },
{ 4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u },
{ 3483374466074094362u, 1392346379889585943u }, { 1884050330976640656u, 2227754207823337509u },
{ 5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u },
{ 5913764258841343181u, 2281220308811097609u }, { 8420360221814984868u, 1824976247048878087u },
{ 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u },
{ 10245762345624985047u, 1868775676978051161u }, { 4507261061758077715u, 1495020541582440929u },
{ 7295157664148372495u, 1196016433265952743u }, { 7982903447895485668u, 1913626293225524389u },
{ 10075671573058298858u, 1530901034580419511u }, { 4371188443704728763u, 1224720827664335609u },
{ 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u },
{ 15839291315758726049u, 1254114127528279663u }, { 3206773216762499739u, 2006582604045247462u },
{ 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u },
{ 4907049252451240275u, 2054740586542333401u }, { 236290587219081897u, 1643792469233866721u },
{ 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u },
{ 5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u },
{ 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u },
{ 12584037722297574282u, 1378913065775496824u }, { 9066413911450387881u, 2206260905240794919u },
{ 10942479943902220628u, 1765008724192635935u }, { 8753983955121776503u, 1412006979354108748u },
{ 10317025513452932081u, 2259211166966573997u }, { 874922781278525018u, 1807368933573259198u },
{ 8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u },
{ 14767872471458792434u, 1850745787979017418u }, { 746251532941302978u, 1480596630383213935u },
{ 597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u },
{ 8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u },
{ 17270291175157100626u, 1940647615375886168u }, { 2748186495899949531u, 1552518092300708935u },
{ 2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u },
{ 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u },
{ 8826220925580526867u, 2034916513940385215u }, { 7060976740464421494u, 1627933211152308172u },
{ 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u },
{ 9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u },
{ 13015147745246481542u, 2133764618521553367u }, { 3033420566713364587u, 1707011694817242694u },
{ 6116085268112601993u, 1365609355853794155u }, { 9785736428980163188u, 2184974969366070648u },
{ 15207286772667951197u, 1747979975492856518u }, { 1097782973908629988u, 1398383980394285215u },
{ 1756452758253807981u, 2237414368630856344u }, { 5094511021344956708u, 1789931494904685075u },
{ 4075608817075965366u, 1431945195923748060u }, { 6520974107321544586u, 2291112313477996896u },
{ 1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u },
{ 17210690286378213644u, 1173049504500734410u }, { 9090360384495590213u, 1876879207201175057u },
{ 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u },
{ 16096930852848599373u, 1921924308174003258u }, { 1809498238053148529u, 1537539446539202607u },
{ 12515645034668249793u, 1230031557231362085u }, { 1578287981759648052u, 1968050491570179337u },
{ 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u },
{ 3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u },
{ 6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u },
{ 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u },
{ 7551343283653851484u, 2113178124542660985u }, { 6041074626923081187u, 1690542499634128788u },
{ 12211557331022285596u, 1352433999707303030u }, { 1091747655926105338u, 2163894399531684849u },
{ 4562746939482794594u, 1731115519625347879u }, { 7339546366328145998u, 1384892415700278303u },
{ 8053925371383123274u, 2215827865120445285u }, { 6443140297106498619u, 1772662292096356228u },
{ 12533209867169019542u, 1418129833677084982u }, { 5295740528502789974u, 2269007733883335972u },
{ 15304638867027962949u, 1815206187106668777u }, { 4865013464138549713u, 1452164949685335022u },
{ 14960057215536570740u, 1161731959748268017u }, { 9178696285890871890u, 1858771135597228828u },
{ 14721654658196518159u, 1487016908477783062u }, { 4398626097073393881u, 1189613526782226450u },
{ 7037801755317430209u, 1903381642851562320u }, { 5630241404253944167u, 1522705314281249856u },
{ 814844308661245011u, 1218164251424999885u }, { 1303750893857992017u, 1949062802279999816u },
{ 15800395974054034906u, 1559250241823999852u }, { 5261619149759407279u, 1247400193459199882u },
{ 12107939454356961969u, 1995840309534719811u }, { 5997002748743659252u, 1596672247627775849u },
{ 8486951013736837725u, 1277337798102220679u }, { 2511075177753209390u, 2043740476963553087u },
{ 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u },
{ 4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u },
{ 3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u },
{ 9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u },
{ 5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u },
{ 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u },
{ 13453306206113055875u, 1797693134862315907u }, { 3383947335406624054u, 1438154507889852726u },
{ 16482362180876329456u, 2301047212623764361u }, { 9496540929959153242u, 1840837770099011489u },
{ 11286581558709232917u, 1472670216079209191u }, { 5339916432225476010u, 1178136172863367353u },
{ 4854517476818851293u, 1885017876581387765u }, { 3883613981455081034u, 1508014301265110212u },
{ 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u },
{ 5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u },
{ 6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u },
{ 12969830440044306787u, 1265014083170691364u }, { 9683682259845159889u, 2024022533073106183u },
{ 15125643437359948558u, 1619218026458484946u }, { 8411165935146048523u, 1295374421166787957u },
{ 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u },
{ 8022738107230848036u, 1326463407274790868u }, { 9147032156827446534u, 2122341451639665389u },
{ 11006974540203867551u, 1697873161311732311u }, { 5116230817421183718u, 1358298529049385849u },
{ 15564666937357714594u, 2173277646479017358u }, { 1383687105660440706u, 1738622117183213887u },
{ 12174996128754083534u, 1390897693746571109u }, { 8411947361780802685u, 2225436309994513775u },
{ 6729557889424642148u, 1780349047995611020u }, { 5383646311539713719u, 1424279238396488816u },
{ 1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u },
{ 16285752362063044992u, 1458461940118004547u }, { 5649904260166615347u, 1166769552094403638u },
{ 5350498001524674232u, 1866831283351045821u }, { 591049586477829062u, 1493465026680836657u },
{ 11540886113407994219u, 1194772021344669325u }, { 18673707743239135u, 1911635234151470921u },
{ 14772334225162232601u, 1529308187321176736u }, { 8128518565387875758u, 1223446549856941389u },
{ 1937583260394870242u, 1957514479771106223u }, { 8928764237799716840u, 1566011583816884978u },
{ 14521709019723594119u, 1252809267053507982u }, { 8477339172590109297u, 2004494827285612772u },
{ 17849917782297818407u, 1603595861828490217u }, { 6901236596354434079u, 1282876689462792174u },
{ 18420676183650915173u, 2052602703140467478u }, { 3668494502695001169u, 1642082162512373983u },
{ 10313493231639821582u, 1313665730009899186u }, { 9122891541139893884u, 2101865168015838698u },
{ 14677010862395735754u, 1681492134412670958u }, { 673562245690857633u, 1345193707530136767u }
};
static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = {
{ 0u, 1152921504606846976u }, { 0u, 1441151880758558720u },
{ 0u, 1801439850948198400u }, { 0u, 2251799813685248000u },
{ 0u, 1407374883553280000u }, { 0u, 1759218604441600000u },
{ 0u, 2199023255552000000u }, { 0u, 1374389534720000000u },
{ 0u, 1717986918400000000u }, { 0u, 2147483648000000000u },
{ 0u, 1342177280000000000u }, { 0u, 1677721600000000000u },
{ 0u, 2097152000000000000u }, { 0u, 1310720000000000000u },
{ 0u, 1638400000000000000u }, { 0u, 2048000000000000000u },
{ 0u, 1280000000000000000u }, { 0u, 1600000000000000000u },
{ 0u, 2000000000000000000u }, { 0u, 1250000000000000000u },
{ 0u, 1562500000000000000u }, { 0u, 1953125000000000000u },
{ 0u, 1220703125000000000u }, { 0u, 1525878906250000000u },
{ 0u, 1907348632812500000u }, { 0u, 1192092895507812500u },
{ 0u, 1490116119384765625u }, { 4611686018427387904u, 1862645149230957031u },
{ 9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u },
{ 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u },
{ 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u },
{ 15629249925580062720u, 2220446049250313080u }, { 9768281203487539200u, 1387778780781445675u },
{ 7598665485932036096u, 1734723475976807094u }, { 274959820560269312u, 2168404344971008868u },
{ 9395221924704944128u, 1355252715606880542u }, { 2520655369026404352u, 1694065894508600678u },
{ 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u },
{ 13702562178731606016u, 1654361225106055349u }, { 3293144668132343808u, 2067951531382569187u },
{ 18199116482078572544u, 1292469707114105741u }, { 8913837547316051968u, 1615587133892632177u },
{ 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u },
{ 15190102943214346240u, 1577721810442023610u }, { 9764256642163156992u, 1972152263052529513u },
{ 17631875447420442880u, 1232595164407830945u }, { 8204786253993389888u, 1540743955509788682u },
{ 1032610780636961552u, 1925929944387235853u }, { 2951224747111794922u, 1203706215242022408u },
{ 3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u },
{ 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u },
{ 3710578054803671186u, 1836709923159824231u }, { 26536550077201078u, 2295887403949780289u },
{ 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u },
{ 8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u },
{ 12076381983474541759u, 1751623080406021338u }, { 5872105442488401391u, 2189528850507526673u },
{ 15199280947623720629u, 1368455531567204170u }, { 9775729147674874978u, 1710569414459005213u },
{ 16831347453020981627u, 2138211768073756516u }, { 1296220121283337709u, 1336382355046097823u },
{ 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u },
{ 6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u },
{ 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u },
{ 532749306367912313u, 1593091911132452277u }, { 5277622651387278295u, 1991364888915565346u },
{ 7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u },
{ 8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u },
{ 10989071563364309441u, 1519290839321567799u }, { 9124653435777998898u, 1899113549151959749u },
{ 8008751406574943263u, 1186945968219974843u }, { 5399253239791291175u, 1483682460274968554u },
{ 15972438586593889776u, 1854603075343710692u }, { 759402079766405302u, 1159126922089819183u },
{ 14784310654990170340u, 1448908652612273978u }, { 9257016281882937117u, 1811135815765342473u },
{ 16182956370781059300u, 2263919769706678091u }, { 7808504722524468110u, 1414949856066673807u },
{ 5148944884728197234u, 1768687320083342259u }, { 1824495087482858639u, 2210859150104177824u },
{ 1140309429676786649u, 1381786968815111140u }, { 1425386787095983311u, 1727233711018888925u },
{ 6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u },
{ 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u },
{ 803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u },
{ 4714634887749086344u, 2059023035787211567u }, { 9864175832484260821u, 1286889397367007229u },
{ 16941905809032713930u, 1608611746708759036u }, { 2730638187581340797u, 2010764683385948796u },
{ 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u },
{ 4396021111970173586u, 1963637386119090621u }, { 5053356204195052443u, 1227273366324431638u },
{ 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u },
{ 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u },
{ 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u },
{ 4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u },
{ 7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u },
{ 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u },
{ 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u },
{ 10956397575869330579u, 2180075438084173168u }, { 6847748484918331612u, 1362547148802608230u },
{ 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u },
{ 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u },
{ 13024893955298202172u, 2079081953128979843u }, { 5834715712847682405u, 1299426220705612402u },
{ 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u },
{ 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u },
{ 12596021324643517422u, 1982767060402850955u }, { 5566670318688504437u, 1239229412751781847u },
{ 2346651879933242642u, 1549036765939727309u }, { 7545000868343941206u, 1936295957424659136u },
{ 4715625542714963254u, 1210184973390411960u }, { 5894531928393704067u, 1512731216738014950u },
{ 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u },
{ 16997363506238734644u, 1477276578845717724u }, { 2799960309088866689u, 1846595723557147156u },
{ 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u },
{ 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u },
{ 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u },
{ 3447025083132431277u, 2201313642927583642u }, { 6766076695385157452u, 1375821026829739776u },
{ 8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u },
{ 6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u },
{ 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u },
{ 5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u },
{ 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u },
{ 7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u },
{ 3885132398186337741u, 1564127418111797597u }, { 9468101516160310080u, 1955159272639746996u },
{ 15140935484454969608u, 1221974545399841872u }, { 479425281859160394u, 1527468181749802341u },
{ 5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u },
{ 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u },
{ 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u },
{ 8047776328842869663u, 1820883967578175474u }, { 836348374198811271u, 2276104959472719343u },
{ 7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u },
{ 8166621051047176104u, 2222758749485077483u }, { 2798295147690791113u, 1389224218428173427u },
{ 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u },
{ 8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u },
{ 3828506775840797949u, 2119787930951192363u }, { 86973725686804766u, 1324867456844495227u },
{ 13943775212390669669u, 1656084321055619033u }, { 3594660960206173375u, 2070105401319523792u },
{ 2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u },
{ 5816254103165035138u, 2021587305976097453u }, { 5941001823691840913u, 1263492066235060908u },
{ 7426252279614801142u, 1579365082793826135u }, { 4671129331091113523u, 1974206353492282669u },
{ 5225298841145639904u, 1233878970932676668u }, { 6531623551432049880u, 1542348713665845835u },
{ 3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u },
{ 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u },
{ 11355826773077190286u, 1176718684132267635u }, { 9583097447919099954u, 1470898355165334544u },
{ 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u },
{ 2440964573842414192u, 1436424174966147016u }, { 3051205717303017741u, 1795530218707683770u },
{ 13037379183483547984u, 2244412773384604712u }, { 8148361989677217490u, 1402757983365377945u },
{ 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u },
{ 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u },
{ 9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u },
{ 3292878744173340370u, 1672217826086733276u }, { 4116098430216675462u, 2090272282608416595u },
{ 266718509671728212u, 1306420176630260372u }, { 333398137089660265u, 1633025220787825465u },
{ 5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u },
{ 12575375104699370472u, 1594751192175610805u }, { 1884160825592049379u, 1993438990219513507u },
{ 17318501580490888525u, 1245899368887195941u }, { 7813068920331446945u, 1557374211108994927u },
{ 5154650131986920777u, 1946717763886243659u }, { 915813323278131534u, 1216698602428902287u },
{ 14979824709379828129u, 1520873253036127858u }, { 9501408849870009354u, 1901091566295159823u },
{ 12855909558809837702u, 1188182228934474889u }, { 2234828893230133415u, 1485227786168093612u },
{ 2793536116537666769u, 1856534732710117015u }, { 8663489100477123587u, 1160334207943823134u },
{ 1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u },
{ 9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u },
{ 16011667041914537212u, 1770529492101780905u }, { 6179525747111007803u, 2213161865127226132u },
{ 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u },
{ 15834525901571292854u, 2161290883913306769u }, { 2979049660840976177u, 1350806802445816731u },
{ 17558870131333383934u, 1688508503057270913u }, { 8113529608884566205u, 2110635628821588642u },
{ 9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u },
{ 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u },
{ 1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u },
{ 4853210475701136017u, 1258036869061940099u }, { 1454827076199032118u, 1572546086327425124u },
{ 1818533845248790147u, 1965682607909281405u }, { 3442426662494187794u, 1228551629943300878u },
{ 13526405364972510550u, 1535689537429126097u }, { 3072948650933474476u, 1919611921786407622u },
{ 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u },
{ 9630225068416591280u, 1874621017369538693u }, { 8324733676974063502u, 1171638135855961683u },
{ 5794231077790191473u, 1464547669819952104u }, { 7242788847237739342u, 1830684587274940130u },
{ 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u },
{ 1596658836748081690u, 1787777917260683721u }, { 6607509564362490017u, 2234722396575854651u },
{ 1823850468512862308u, 1396701497859909157u }, { 6891499104068465790u, 1745876872324886446u },
{ 17837745916940358045u, 2182346090406108057u }, { 4231062170446641922u, 1363966306503817536u },
{ 5288827713058302403u, 1704957883129771920u }, { 6611034641322878003u, 2131197353912214900u },
{ 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u },
{ 11644235287647684442u, 2081247415929897363u }, { 4971804045566108824u, 1300779634956185852u },
{ 6214755056957636030u, 1625974543695232315u }, { 3156757802769657134u, 2032468179619040394u },
{ 6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u },
{ 17206059723201118751u, 1984832206659219134u }, { 6142101308573311315u, 1240520129162011959u },
{ 3065940617289251240u, 1550650161452514949u }, { 8444111790038951954u, 1938312701815643686u },
{ 665883850346957067u, 1211445438634777304u }, { 832354812933696334u, 1514306798293471630u },
{ 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u },
{ 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u },
{ 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u },
{ 1277659885424598868u, 1805194375864829576u }, { 1597074856780748586u, 2256492969831036970u },
{ 5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u },
{ 1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u },
{ 11243484188358716120u, 1721567512383298469u }, { 219297180166231438u, 2151959390479123087u },
{ 7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u },
{ 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u },
{ 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u },
{ 16925056528170176201u, 1282667750405742577u }, { 7321262604930556539u, 1603334688007178222u },
{ 18374950293017971482u, 2004168360008972777u }, { 4566814905495150320u, 1252605225005607986u },
{ 14931890668723713708u, 1565756531257009982u }, { 9441491299049866327u, 1957195664071262478u },
{ 1289246043478778550u, 1223247290044539049u }, { 6223243572775861092u, 1529059112555673811u },
{ 3167368447542438461u, 1911323890694592264u }, { 1979605279714024038u, 1194577431684120165u },
{ 7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u },
{ 13606538515115052232u, 1166579523129023598u }, { 7784801107039039482u, 1458224403911279498u },
{ 507629346944023544u, 1822780504889099373u }, { 5246222702107417334u, 2278475631111374216u },
{ 3278889188817135834u, 1424047269444608885u }, { 8710297504448807696u, 1780059086805761106u }
};
#endif // RYU_TAB_H

View file

@ -16,7 +16,6 @@
#include "native.h" #include "native.h"
#include "utf8.h" #include "utf8.h"
#include "test/xprintf.h"
static const uint64_t ODD_MASK = 0xaaaaaaaaaaaaaaaa; static const uint64_t ODD_MASK = 0xaaaaaaaaaaaaaaaa;
static const uint64_t EVEN_MASK = 0x5555555555555555; static const uint64_t EVEN_MASK = 0x5555555555555555;

695
native/tab.h Normal file
View file

@ -0,0 +1,695 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TAB_H
#define TAB_H
#include "test/xassert.h"
struct uint64x2 {
uint64_t hi;
uint64_t lo;
};
typedef struct uint64x2 uint64x2;
static const char Digits[200] = {
'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',
};
static inline bool is_div_pow2(uint64_t val, int32_t e) {
xassert(e >= 0 && e <= 63);
uint64_t mask = (1ull << e) - 1;
return (val & mask) == 0;
}
static inline char* utoa2(char* p, uint32_t val) {
p[0] = Digits[val];
p[1] = Digits[val + 1];
return p + 2;
}
static inline void copy_two_digs(char* dst, const char* src) {
*(dst) = *(src);
*(dst + 1) = *(src + 1);
}
static inline const uint64x2 pow10_ceil_sig(int32_t k) {
// There are unique beta and r such that 10^k = beta 2^r and
// 2^127 <= beta < 2^128, namely r = floor(log_2 10^k) - 127 and
// beta = 2^-r 10^k.
// Let g = ceil(beta), so (g-1) 2^r < 10^k <= g 2^r, with the latter
// value being a pretty good overestimate for 10^k.
// NB: Since for all the required exponents k, we have g < 2^128,
// all constants can be stored in 128-bit integers.
// Reference from:
// https://github.com/abolz/Drachennest/blob/master/src/schubfach_64.cc#L151
#define KMIN -292
#define KMAX 324
static const uint64x2 g[KMAX - KMIN + 1] = {
{0xFF77B1FCBEBCDC4F, 0x25E8E89C13BB0F7B}, // -292
{0x9FAACF3DF73609B1, 0x77B191618C54E9AD}, // -291
{0xC795830D75038C1D, 0xD59DF5B9EF6A2418}, // -290
{0xF97AE3D0D2446F25, 0x4B0573286B44AD1E}, // -289
{0x9BECCE62836AC577, 0x4EE367F9430AEC33}, // -288
{0xC2E801FB244576D5, 0x229C41F793CDA740}, // -287
{0xF3A20279ED56D48A, 0x6B43527578C11110}, // -286
{0x9845418C345644D6, 0x830A13896B78AAAA}, // -285
{0xBE5691EF416BD60C, 0x23CC986BC656D554}, // -284
{0xEDEC366B11C6CB8F, 0x2CBFBE86B7EC8AA9}, // -283
{0x94B3A202EB1C3F39, 0x7BF7D71432F3D6AA}, // -282
{0xB9E08A83A5E34F07, 0xDAF5CCD93FB0CC54}, // -281
{0xE858AD248F5C22C9, 0xD1B3400F8F9CFF69}, // -280
{0x91376C36D99995BE, 0x23100809B9C21FA2}, // -279
{0xB58547448FFFFB2D, 0xABD40A0C2832A78B}, // -278
{0xE2E69915B3FFF9F9, 0x16C90C8F323F516D}, // -277
{0x8DD01FAD907FFC3B, 0xAE3DA7D97F6792E4}, // -276
{0xB1442798F49FFB4A, 0x99CD11CFDF41779D}, // -275
{0xDD95317F31C7FA1D, 0x40405643D711D584}, // -274
{0x8A7D3EEF7F1CFC52, 0x482835EA666B2573}, // -273
{0xAD1C8EAB5EE43B66, 0xDA3243650005EED0}, // -272
{0xD863B256369D4A40, 0x90BED43E40076A83}, // -271
{0x873E4F75E2224E68, 0x5A7744A6E804A292}, // -270
{0xA90DE3535AAAE202, 0x711515D0A205CB37}, // -269
{0xD3515C2831559A83, 0x0D5A5B44CA873E04}, // -268
{0x8412D9991ED58091, 0xE858790AFE9486C3}, // -267
{0xA5178FFF668AE0B6, 0x626E974DBE39A873}, // -266
{0xCE5D73FF402D98E3, 0xFB0A3D212DC81290}, // -265
{0x80FA687F881C7F8E, 0x7CE66634BC9D0B9A}, // -264
{0xA139029F6A239F72, 0x1C1FFFC1EBC44E81}, // -263
{0xC987434744AC874E, 0xA327FFB266B56221}, // -262
{0xFBE9141915D7A922, 0x4BF1FF9F0062BAA9}, // -261
{0x9D71AC8FADA6C9B5, 0x6F773FC3603DB4AA}, // -260
{0xC4CE17B399107C22, 0xCB550FB4384D21D4}, // -259
{0xF6019DA07F549B2B, 0x7E2A53A146606A49}, // -258
{0x99C102844F94E0FB, 0x2EDA7444CBFC426E}, // -257
{0xC0314325637A1939, 0xFA911155FEFB5309}, // -256
{0xF03D93EEBC589F88, 0x793555AB7EBA27CB}, // -255
{0x96267C7535B763B5, 0x4BC1558B2F3458DF}, // -254
{0xBBB01B9283253CA2, 0x9EB1AAEDFB016F17}, // -253
{0xEA9C227723EE8BCB, 0x465E15A979C1CADD}, // -252
{0x92A1958A7675175F, 0x0BFACD89EC191ECA}, // -251
{0xB749FAED14125D36, 0xCEF980EC671F667C}, // -250
{0xE51C79A85916F484, 0x82B7E12780E7401B}, // -249
{0x8F31CC0937AE58D2, 0xD1B2ECB8B0908811}, // -248
{0xB2FE3F0B8599EF07, 0x861FA7E6DCB4AA16}, // -247
{0xDFBDCECE67006AC9, 0x67A791E093E1D49B}, // -246
{0x8BD6A141006042BD, 0xE0C8BB2C5C6D24E1}, // -245
{0xAECC49914078536D, 0x58FAE9F773886E19}, // -244
{0xDA7F5BF590966848, 0xAF39A475506A899F}, // -243
{0x888F99797A5E012D, 0x6D8406C952429604}, // -242
{0xAAB37FD7D8F58178, 0xC8E5087BA6D33B84}, // -241
{0xD5605FCDCF32E1D6, 0xFB1E4A9A90880A65}, // -240
{0x855C3BE0A17FCD26, 0x5CF2EEA09A550680}, // -239
{0xA6B34AD8C9DFC06F, 0xF42FAA48C0EA481F}, // -238
{0xD0601D8EFC57B08B, 0xF13B94DAF124DA27}, // -237
{0x823C12795DB6CE57, 0x76C53D08D6B70859}, // -236
{0xA2CB1717B52481ED, 0x54768C4B0C64CA6F}, // -235
{0xCB7DDCDDA26DA268, 0xA9942F5DCF7DFD0A}, // -234
{0xFE5D54150B090B02, 0xD3F93B35435D7C4D}, // -233
{0x9EFA548D26E5A6E1, 0xC47BC5014A1A6DB0}, // -232
{0xC6B8E9B0709F109A, 0x359AB6419CA1091C}, // -231
{0xF867241C8CC6D4C0, 0xC30163D203C94B63}, // -230
{0x9B407691D7FC44F8, 0x79E0DE63425DCF1E}, // -229
{0xC21094364DFB5636, 0x985915FC12F542E5}, // -228
{0xF294B943E17A2BC4, 0x3E6F5B7B17B2939E}, // -227
{0x979CF3CA6CEC5B5A, 0xA705992CEECF9C43}, // -226
{0xBD8430BD08277231, 0x50C6FF782A838354}, // -225
{0xECE53CEC4A314EBD, 0xA4F8BF5635246429}, // -224
{0x940F4613AE5ED136, 0x871B7795E136BE9A}, // -223
{0xB913179899F68584, 0x28E2557B59846E40}, // -222
{0xE757DD7EC07426E5, 0x331AEADA2FE589D0}, // -221
{0x9096EA6F3848984F, 0x3FF0D2C85DEF7622}, // -220
{0xB4BCA50B065ABE63, 0x0FED077A756B53AA}, // -219
{0xE1EBCE4DC7F16DFB, 0xD3E8495912C62895}, // -218
{0x8D3360F09CF6E4BD, 0x64712DD7ABBBD95D}, // -217
{0xB080392CC4349DEC, 0xBD8D794D96AACFB4}, // -216
{0xDCA04777F541C567, 0xECF0D7A0FC5583A1}, // -215
{0x89E42CAAF9491B60, 0xF41686C49DB57245}, // -214
{0xAC5D37D5B79B6239, 0x311C2875C522CED6}, // -213
{0xD77485CB25823AC7, 0x7D633293366B828C}, // -212
{0x86A8D39EF77164BC, 0xAE5DFF9C02033198}, // -211
{0xA8530886B54DBDEB, 0xD9F57F830283FDFD}, // -210
{0xD267CAA862A12D66, 0xD072DF63C324FD7C}, // -209
{0x8380DEA93DA4BC60, 0x4247CB9E59F71E6E}, // -208
{0xA46116538D0DEB78, 0x52D9BE85F074E609}, // -207
{0xCD795BE870516656, 0x67902E276C921F8C}, // -206
{0x806BD9714632DFF6, 0x00BA1CD8A3DB53B7}, // -205
{0xA086CFCD97BF97F3, 0x80E8A40ECCD228A5}, // -204
{0xC8A883C0FDAF7DF0, 0x6122CD128006B2CE}, // -203
{0xFAD2A4B13D1B5D6C, 0x796B805720085F82}, // -202
{0x9CC3A6EEC6311A63, 0xCBE3303674053BB1}, // -201
{0xC3F490AA77BD60FC, 0xBEDBFC4411068A9D}, // -200
{0xF4F1B4D515ACB93B, 0xEE92FB5515482D45}, // -199
{0x991711052D8BF3C5, 0x751BDD152D4D1C4B}, // -198
{0xBF5CD54678EEF0B6, 0xD262D45A78A0635E}, // -197
{0xEF340A98172AACE4, 0x86FB897116C87C35}, // -196
{0x9580869F0E7AAC0E, 0xD45D35E6AE3D4DA1}, // -195
{0xBAE0A846D2195712, 0x8974836059CCA10A}, // -194
{0xE998D258869FACD7, 0x2BD1A438703FC94C}, // -193
{0x91FF83775423CC06, 0x7B6306A34627DDD0}, // -192
{0xB67F6455292CBF08, 0x1A3BC84C17B1D543}, // -191
{0xE41F3D6A7377EECA, 0x20CABA5F1D9E4A94}, // -190
{0x8E938662882AF53E, 0x547EB47B7282EE9D}, // -189
{0xB23867FB2A35B28D, 0xE99E619A4F23AA44}, // -188
{0xDEC681F9F4C31F31, 0x6405FA00E2EC94D5}, // -187
{0x8B3C113C38F9F37E, 0xDE83BC408DD3DD05}, // -186
{0xAE0B158B4738705E, 0x9624AB50B148D446}, // -185
{0xD98DDAEE19068C76, 0x3BADD624DD9B0958}, // -184
{0x87F8A8D4CFA417C9, 0xE54CA5D70A80E5D7}, // -183
{0xA9F6D30A038D1DBC, 0x5E9FCF4CCD211F4D}, // -182
{0xD47487CC8470652B, 0x7647C32000696720}, // -181
{0x84C8D4DFD2C63F3B, 0x29ECD9F40041E074}, // -180
{0xA5FB0A17C777CF09, 0xF468107100525891}, // -179
{0xCF79CC9DB955C2CC, 0x7182148D4066EEB5}, // -178
{0x81AC1FE293D599BF, 0xC6F14CD848405531}, // -177
{0xA21727DB38CB002F, 0xB8ADA00E5A506A7D}, // -176
{0xCA9CF1D206FDC03B, 0xA6D90811F0E4851D}, // -175
{0xFD442E4688BD304A, 0x908F4A166D1DA664}, // -174
{0x9E4A9CEC15763E2E, 0x9A598E4E043287FF}, // -173
{0xC5DD44271AD3CDBA, 0x40EFF1E1853F29FE}, // -172
{0xF7549530E188C128, 0xD12BEE59E68EF47D}, // -171
{0x9A94DD3E8CF578B9, 0x82BB74F8301958CF}, // -170
{0xC13A148E3032D6E7, 0xE36A52363C1FAF02}, // -169
{0xF18899B1BC3F8CA1, 0xDC44E6C3CB279AC2}, // -168
{0x96F5600F15A7B7E5, 0x29AB103A5EF8C0BA}, // -167
{0xBCB2B812DB11A5DE, 0x7415D448F6B6F0E8}, // -166
{0xEBDF661791D60F56, 0x111B495B3464AD22}, // -165
{0x936B9FCEBB25C995, 0xCAB10DD900BEEC35}, // -164
{0xB84687C269EF3BFB, 0x3D5D514F40EEA743}, // -163
{0xE65829B3046B0AFA, 0x0CB4A5A3112A5113}, // -162
{0x8FF71A0FE2C2E6DC, 0x47F0E785EABA72AC}, // -161
{0xB3F4E093DB73A093, 0x59ED216765690F57}, // -160
{0xE0F218B8D25088B8, 0x306869C13EC3532D}, // -159
{0x8C974F7383725573, 0x1E414218C73A13FC}, // -158
{0xAFBD2350644EEACF, 0xE5D1929EF90898FB}, // -157
{0xDBAC6C247D62A583, 0xDF45F746B74ABF3A}, // -156
{0x894BC396CE5DA772, 0x6B8BBA8C328EB784}, // -155
{0xAB9EB47C81F5114F, 0x066EA92F3F326565}, // -154
{0xD686619BA27255A2, 0xC80A537B0EFEFEBE}, // -153
{0x8613FD0145877585, 0xBD06742CE95F5F37}, // -152
{0xA798FC4196E952E7, 0x2C48113823B73705}, // -151
{0xD17F3B51FCA3A7A0, 0xF75A15862CA504C6}, // -150
{0x82EF85133DE648C4, 0x9A984D73DBE722FC}, // -149
{0xA3AB66580D5FDAF5, 0xC13E60D0D2E0EBBB}, // -148
{0xCC963FEE10B7D1B3, 0x318DF905079926A9}, // -147
{0xFFBBCFE994E5C61F, 0xFDF17746497F7053}, // -146
{0x9FD561F1FD0F9BD3, 0xFEB6EA8BEDEFA634}, // -145
{0xC7CABA6E7C5382C8, 0xFE64A52EE96B8FC1}, // -144
{0xF9BD690A1B68637B, 0x3DFDCE7AA3C673B1}, // -143
{0x9C1661A651213E2D, 0x06BEA10CA65C084F}, // -142
{0xC31BFA0FE5698DB8, 0x486E494FCFF30A63}, // -141
{0xF3E2F893DEC3F126, 0x5A89DBA3C3EFCCFB}, // -140
{0x986DDB5C6B3A76B7, 0xF89629465A75E01D}, // -139
{0xBE89523386091465, 0xF6BBB397F1135824}, // -138
{0xEE2BA6C0678B597F, 0x746AA07DED582E2D}, // -137
{0x94DB483840B717EF, 0xA8C2A44EB4571CDD}, // -136
{0xBA121A4650E4DDEB, 0x92F34D62616CE414}, // -135
{0xE896A0D7E51E1566, 0x77B020BAF9C81D18}, // -134
{0x915E2486EF32CD60, 0x0ACE1474DC1D122F}, // -133
{0xB5B5ADA8AAFF80B8, 0x0D819992132456BB}, // -132
{0xE3231912D5BF60E6, 0x10E1FFF697ED6C6A}, // -131
{0x8DF5EFABC5979C8F, 0xCA8D3FFA1EF463C2}, // -130
{0xB1736B96B6FD83B3, 0xBD308FF8A6B17CB3}, // -129
{0xDDD0467C64BCE4A0, 0xAC7CB3F6D05DDBDF}, // -128
{0x8AA22C0DBEF60EE4, 0x6BCDF07A423AA96C}, // -127
{0xAD4AB7112EB3929D, 0x86C16C98D2C953C7}, // -126
{0xD89D64D57A607744, 0xE871C7BF077BA8B8}, // -125
{0x87625F056C7C4A8B, 0x11471CD764AD4973}, // -124
{0xA93AF6C6C79B5D2D, 0xD598E40D3DD89BD0}, // -123
{0xD389B47879823479, 0x4AFF1D108D4EC2C4}, // -122
{0x843610CB4BF160CB, 0xCEDF722A585139BB}, // -121
{0xA54394FE1EEDB8FE, 0xC2974EB4EE658829}, // -120
{0xCE947A3DA6A9273E, 0x733D226229FEEA33}, // -119
{0x811CCC668829B887, 0x0806357D5A3F5260}, // -118
{0xA163FF802A3426A8, 0xCA07C2DCB0CF26F8}, // -117
{0xC9BCFF6034C13052, 0xFC89B393DD02F0B6}, // -116
{0xFC2C3F3841F17C67, 0xBBAC2078D443ACE3}, // -115
{0x9D9BA7832936EDC0, 0xD54B944B84AA4C0E}, // -114
{0xC5029163F384A931, 0x0A9E795E65D4DF12}, // -113
{0xF64335BCF065D37D, 0x4D4617B5FF4A16D6}, // -112
{0x99EA0196163FA42E, 0x504BCED1BF8E4E46}, // -111
{0xC06481FB9BCF8D39, 0xE45EC2862F71E1D7}, // -110
{0xF07DA27A82C37088, 0x5D767327BB4E5A4D}, // -109
{0x964E858C91BA2655, 0x3A6A07F8D510F870}, // -108
{0xBBE226EFB628AFEA, 0x890489F70A55368C}, // -107
{0xEADAB0ABA3B2DBE5, 0x2B45AC74CCEA842F}, // -106
{0x92C8AE6B464FC96F, 0x3B0B8BC90012929E}, // -105
{0xB77ADA0617E3BBCB, 0x09CE6EBB40173745}, // -104
{0xE55990879DDCAABD, 0xCC420A6A101D0516}, // -103
{0x8F57FA54C2A9EAB6, 0x9FA946824A12232E}, // -102
{0xB32DF8E9F3546564, 0x47939822DC96ABFA}, // -101
{0xDFF9772470297EBD, 0x59787E2B93BC56F8}, // -100
{0x8BFBEA76C619EF36, 0x57EB4EDB3C55B65B}, // -99
{0xAEFAE51477A06B03, 0xEDE622920B6B23F2}, // -98
{0xDAB99E59958885C4, 0xE95FAB368E45ECEE}, // -97
{0x88B402F7FD75539B, 0x11DBCB0218EBB415}, // -96
{0xAAE103B5FCD2A881, 0xD652BDC29F26A11A}, // -95
{0xD59944A37C0752A2, 0x4BE76D3346F04960}, // -94
{0x857FCAE62D8493A5, 0x6F70A4400C562DDC}, // -93
{0xA6DFBD9FB8E5B88E, 0xCB4CCD500F6BB953}, // -92
{0xD097AD07A71F26B2, 0x7E2000A41346A7A8}, // -91
{0x825ECC24C873782F, 0x8ED400668C0C28C9}, // -90
{0xA2F67F2DFA90563B, 0x728900802F0F32FB}, // -89
{0xCBB41EF979346BCA, 0x4F2B40A03AD2FFBA}, // -88
{0xFEA126B7D78186BC, 0xE2F610C84987BFA9}, // -87
{0x9F24B832E6B0F436, 0x0DD9CA7D2DF4D7CA}, // -86
{0xC6EDE63FA05D3143, 0x91503D1C79720DBC}, // -85
{0xF8A95FCF88747D94, 0x75A44C6397CE912B}, // -84
{0x9B69DBE1B548CE7C, 0xC986AFBE3EE11ABB}, // -83
{0xC24452DA229B021B, 0xFBE85BADCE996169}, // -82
{0xF2D56790AB41C2A2, 0xFAE27299423FB9C4}, // -81
{0x97C560BA6B0919A5, 0xDCCD879FC967D41B}, // -80
{0xBDB6B8E905CB600F, 0x5400E987BBC1C921}, // -79
{0xED246723473E3813, 0x290123E9AAB23B69}, // -78
{0x9436C0760C86E30B, 0xF9A0B6720AAF6522}, // -77
{0xB94470938FA89BCE, 0xF808E40E8D5B3E6A}, // -76
{0xE7958CB87392C2C2, 0xB60B1D1230B20E05}, // -75
{0x90BD77F3483BB9B9, 0xB1C6F22B5E6F48C3}, // -74
{0xB4ECD5F01A4AA828, 0x1E38AEB6360B1AF4}, // -73
{0xE2280B6C20DD5232, 0x25C6DA63C38DE1B1}, // -72
{0x8D590723948A535F, 0x579C487E5A38AD0F}, // -71
{0xB0AF48EC79ACE837, 0x2D835A9DF0C6D852}, // -70
{0xDCDB1B2798182244, 0xF8E431456CF88E66}, // -69
{0x8A08F0F8BF0F156B, 0x1B8E9ECB641B5900}, // -68
{0xAC8B2D36EED2DAC5, 0xE272467E3D222F40}, // -67
{0xD7ADF884AA879177, 0x5B0ED81DCC6ABB10}, // -66
{0x86CCBB52EA94BAEA, 0x98E947129FC2B4EA}, // -65
{0xA87FEA27A539E9A5, 0x3F2398D747B36225}, // -64
{0xD29FE4B18E88640E, 0x8EEC7F0D19A03AAE}, // -63
{0x83A3EEEEF9153E89, 0x1953CF68300424AD}, // -62
{0xA48CEAAAB75A8E2B, 0x5FA8C3423C052DD8}, // -61
{0xCDB02555653131B6, 0x3792F412CB06794E}, // -60
{0x808E17555F3EBF11, 0xE2BBD88BBEE40BD1}, // -59
{0xA0B19D2AB70E6ED6, 0x5B6ACEAEAE9D0EC5}, // -58
{0xC8DE047564D20A8B, 0xF245825A5A445276}, // -57
{0xFB158592BE068D2E, 0xEED6E2F0F0D56713}, // -56
{0x9CED737BB6C4183D, 0x55464DD69685606C}, // -55
{0xC428D05AA4751E4C, 0xAA97E14C3C26B887}, // -54
{0xF53304714D9265DF, 0xD53DD99F4B3066A9}, // -53
{0x993FE2C6D07B7FAB, 0xE546A8038EFE402A}, // -52
{0xBF8FDB78849A5F96, 0xDE98520472BDD034}, // -51
{0xEF73D256A5C0F77C, 0x963E66858F6D4441}, // -50
{0x95A8637627989AAD, 0xDDE7001379A44AA9}, // -49
{0xBB127C53B17EC159, 0x5560C018580D5D53}, // -48
{0xE9D71B689DDE71AF, 0xAAB8F01E6E10B4A7}, // -47
{0x9226712162AB070D, 0xCAB3961304CA70E9}, // -46
{0xB6B00D69BB55C8D1, 0x3D607B97C5FD0D23}, // -45
{0xE45C10C42A2B3B05, 0x8CB89A7DB77C506B}, // -44
{0x8EB98A7A9A5B04E3, 0x77F3608E92ADB243}, // -43
{0xB267ED1940F1C61C, 0x55F038B237591ED4}, // -42
{0xDF01E85F912E37A3, 0x6B6C46DEC52F6689}, // -41
{0x8B61313BBABCE2C6, 0x2323AC4B3B3DA016}, // -40
{0xAE397D8AA96C1B77, 0xABEC975E0A0D081B}, // -39
{0xD9C7DCED53C72255, 0x96E7BD358C904A22}, // -38
{0x881CEA14545C7575, 0x7E50D64177DA2E55}, // -37
{0xAA242499697392D2, 0xDDE50BD1D5D0B9EA}, // -36
{0xD4AD2DBFC3D07787, 0x955E4EC64B44E865}, // -35
{0x84EC3C97DA624AB4, 0xBD5AF13BEF0B113F}, // -34
{0xA6274BBDD0FADD61, 0xECB1AD8AEACDD58F}, // -33
{0xCFB11EAD453994BA, 0x67DE18EDA5814AF3}, // -32
{0x81CEB32C4B43FCF4, 0x80EACF948770CED8}, // -31
{0xA2425FF75E14FC31, 0xA1258379A94D028E}, // -30
{0xCAD2F7F5359A3B3E, 0x096EE45813A04331}, // -29
{0xFD87B5F28300CA0D, 0x8BCA9D6E188853FD}, // -28
{0x9E74D1B791E07E48, 0x775EA264CF55347E}, // -27
{0xC612062576589DDA, 0x95364AFE032A819E}, // -26
{0xF79687AED3EEC551, 0x3A83DDBD83F52205}, // -25
{0x9ABE14CD44753B52, 0xC4926A9672793543}, // -24
{0xC16D9A0095928A27, 0x75B7053C0F178294}, // -23
{0xF1C90080BAF72CB1, 0x5324C68B12DD6339}, // -22
{0x971DA05074DA7BEE, 0xD3F6FC16EBCA5E04}, // -21
{0xBCE5086492111AEA, 0x88F4BB1CA6BCF585}, // -20
{0xEC1E4A7DB69561A5, 0x2B31E9E3D06C32E6}, // -19
{0x9392EE8E921D5D07, 0x3AFF322E62439FD0}, // -18
{0xB877AA3236A4B449, 0x09BEFEB9FAD487C3}, // -17
{0xE69594BEC44DE15B, 0x4C2EBE687989A9B4}, // -16
{0x901D7CF73AB0ACD9, 0x0F9D37014BF60A11}, // -15
{0xB424DC35095CD80F, 0x538484C19EF38C95}, // -14
{0xE12E13424BB40E13, 0x2865A5F206B06FBA}, // -13
{0x8CBCCC096F5088CB, 0xF93F87B7442E45D4}, // -12
{0xAFEBFF0BCB24AAFE, 0xF78F69A51539D749}, // -11
{0xDBE6FECEBDEDD5BE, 0xB573440E5A884D1C}, // -10
{0x89705F4136B4A597, 0x31680A88F8953031}, // -9
{0xABCC77118461CEFC, 0xFDC20D2B36BA7C3E}, // -8
{0xD6BF94D5E57A42BC, 0x3D32907604691B4D}, // -7
{0x8637BD05AF6C69B5, 0xA63F9A49C2C1B110}, // -6
{0xA7C5AC471B478423, 0x0FCF80DC33721D54}, // -5
{0xD1B71758E219652B, 0xD3C36113404EA4A9}, // -4
{0x83126E978D4FDF3B, 0x645A1CAC083126EA}, // -3
{0xA3D70A3D70A3D70A, 0x3D70A3D70A3D70A4}, // -2
{0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCD}, // -1
{0x8000000000000000, 0x0000000000000000}, // 0
{0xA000000000000000, 0x0000000000000000}, // 1
{0xC800000000000000, 0x0000000000000000}, // 2
{0xFA00000000000000, 0x0000000000000000}, // 3
{0x9C40000000000000, 0x0000000000000000}, // 4
{0xC350000000000000, 0x0000000000000000}, // 5
{0xF424000000000000, 0x0000000000000000}, // 6
{0x9896800000000000, 0x0000000000000000}, // 7
{0xBEBC200000000000, 0x0000000000000000}, // 8
{0xEE6B280000000000, 0x0000000000000000}, // 9
{0x9502F90000000000, 0x0000000000000000}, // 10
{0xBA43B74000000000, 0x0000000000000000}, // 11
{0xE8D4A51000000000, 0x0000000000000000}, // 12
{0x9184E72A00000000, 0x0000000000000000}, // 13
{0xB5E620F480000000, 0x0000000000000000}, // 14
{0xE35FA931A0000000, 0x0000000000000000}, // 15
{0x8E1BC9BF04000000, 0x0000000000000000}, // 16
{0xB1A2BC2EC5000000, 0x0000000000000000}, // 17
{0xDE0B6B3A76400000, 0x0000000000000000}, // 18
{0x8AC7230489E80000, 0x0000000000000000}, // 19
{0xAD78EBC5AC620000, 0x0000000000000000}, // 20
{0xD8D726B7177A8000, 0x0000000000000000}, // 21
{0x878678326EAC9000, 0x0000000000000000}, // 22
{0xA968163F0A57B400, 0x0000000000000000}, // 23
{0xD3C21BCECCEDA100, 0x0000000000000000}, // 24
{0x84595161401484A0, 0x0000000000000000}, // 25
{0xA56FA5B99019A5C8, 0x0000000000000000}, // 26
{0xCECB8F27F4200F3A, 0x0000000000000000}, // 27
{0x813F3978F8940984, 0x4000000000000000}, // 28
{0xA18F07D736B90BE5, 0x5000000000000000}, // 29
{0xC9F2C9CD04674EDE, 0xA400000000000000}, // 30
{0xFC6F7C4045812296, 0x4D00000000000000}, // 31
{0x9DC5ADA82B70B59D, 0xF020000000000000}, // 32
{0xC5371912364CE305, 0x6C28000000000000}, // 33
{0xF684DF56C3E01BC6, 0xC732000000000000}, // 34
{0x9A130B963A6C115C, 0x3C7F400000000000}, // 35
{0xC097CE7BC90715B3, 0x4B9F100000000000}, // 36
{0xF0BDC21ABB48DB20, 0x1E86D40000000000}, // 37
{0x96769950B50D88F4, 0x1314448000000000}, // 38
{0xBC143FA4E250EB31, 0x17D955A000000000}, // 39
{0xEB194F8E1AE525FD, 0x5DCFAB0800000000}, // 40
{0x92EFD1B8D0CF37BE, 0x5AA1CAE500000000}, // 41
{0xB7ABC627050305AD, 0xF14A3D9E40000000}, // 42
{0xE596B7B0C643C719, 0x6D9CCD05D0000000}, // 43
{0x8F7E32CE7BEA5C6F, 0xE4820023A2000000}, // 44
{0xB35DBF821AE4F38B, 0xDDA2802C8A800000}, // 45
{0xE0352F62A19E306E, 0xD50B2037AD200000}, // 46
{0x8C213D9DA502DE45, 0x4526F422CC340000}, // 47
{0xAF298D050E4395D6, 0x9670B12B7F410000}, // 48
{0xDAF3F04651D47B4C, 0x3C0CDD765F114000}, // 49
{0x88D8762BF324CD0F, 0xA5880A69FB6AC800}, // 50
{0xAB0E93B6EFEE0053, 0x8EEA0D047A457A00}, // 51
{0xD5D238A4ABE98068, 0x72A4904598D6D880}, // 52
{0x85A36366EB71F041, 0x47A6DA2B7F864750}, // 53
{0xA70C3C40A64E6C51, 0x999090B65F67D924}, // 54
{0xD0CF4B50CFE20765, 0xFFF4B4E3F741CF6D}, // 55
{0x82818F1281ED449F, 0xBFF8F10E7A8921A5}, // 56
{0xA321F2D7226895C7, 0xAFF72D52192B6A0E}, // 57
{0xCBEA6F8CEB02BB39, 0x9BF4F8A69F764491}, // 58
{0xFEE50B7025C36A08, 0x02F236D04753D5B5}, // 59
{0x9F4F2726179A2245, 0x01D762422C946591}, // 60
{0xC722F0EF9D80AAD6, 0x424D3AD2B7B97EF6}, // 61
{0xF8EBAD2B84E0D58B, 0xD2E0898765A7DEB3}, // 62
{0x9B934C3B330C8577, 0x63CC55F49F88EB30}, // 63
{0xC2781F49FFCFA6D5, 0x3CBF6B71C76B25FC}, // 64
{0xF316271C7FC3908A, 0x8BEF464E3945EF7B}, // 65
{0x97EDD871CFDA3A56, 0x97758BF0E3CBB5AD}, // 66
{0xBDE94E8E43D0C8EC, 0x3D52EEED1CBEA318}, // 67
{0xED63A231D4C4FB27, 0x4CA7AAA863EE4BDE}, // 68
{0x945E455F24FB1CF8, 0x8FE8CAA93E74EF6B}, // 69
{0xB975D6B6EE39E436, 0xB3E2FD538E122B45}, // 70
{0xE7D34C64A9C85D44, 0x60DBBCA87196B617}, // 71
{0x90E40FBEEA1D3A4A, 0xBC8955E946FE31CE}, // 72
{0xB51D13AEA4A488DD, 0x6BABAB6398BDBE42}, // 73
{0xE264589A4DCDAB14, 0xC696963C7EED2DD2}, // 74
{0x8D7EB76070A08AEC, 0xFC1E1DE5CF543CA3}, // 75
{0xB0DE65388CC8ADA8, 0x3B25A55F43294BCC}, // 76
{0xDD15FE86AFFAD912, 0x49EF0EB713F39EBF}, // 77
{0x8A2DBF142DFCC7AB, 0x6E3569326C784338}, // 78
{0xACB92ED9397BF996, 0x49C2C37F07965405}, // 79
{0xD7E77A8F87DAF7FB, 0xDC33745EC97BE907}, // 80
{0x86F0AC99B4E8DAFD, 0x69A028BB3DED71A4}, // 81
{0xA8ACD7C0222311BC, 0xC40832EA0D68CE0D}, // 82
{0xD2D80DB02AABD62B, 0xF50A3FA490C30191}, // 83
{0x83C7088E1AAB65DB, 0x792667C6DA79E0FB}, // 84
{0xA4B8CAB1A1563F52, 0x577001B891185939}, // 85
{0xCDE6FD5E09ABCF26, 0xED4C0226B55E6F87}, // 86
{0x80B05E5AC60B6178, 0x544F8158315B05B5}, // 87
{0xA0DC75F1778E39D6, 0x696361AE3DB1C722}, // 88
{0xC913936DD571C84C, 0x03BC3A19CD1E38EA}, // 89
{0xFB5878494ACE3A5F, 0x04AB48A04065C724}, // 90
{0x9D174B2DCEC0E47B, 0x62EB0D64283F9C77}, // 91
{0xC45D1DF942711D9A, 0x3BA5D0BD324F8395}, // 92
{0xF5746577930D6500, 0xCA8F44EC7EE3647A}, // 93
{0x9968BF6ABBE85F20, 0x7E998B13CF4E1ECC}, // 94
{0xBFC2EF456AE276E8, 0x9E3FEDD8C321A67F}, // 95
{0xEFB3AB16C59B14A2, 0xC5CFE94EF3EA101F}, // 96
{0x95D04AEE3B80ECE5, 0xBBA1F1D158724A13}, // 97
{0xBB445DA9CA61281F, 0x2A8A6E45AE8EDC98}, // 98
{0xEA1575143CF97226, 0xF52D09D71A3293BE}, // 99
{0x924D692CA61BE758, 0x593C2626705F9C57}, // 100
{0xB6E0C377CFA2E12E, 0x6F8B2FB00C77836D}, // 101
{0xE498F455C38B997A, 0x0B6DFB9C0F956448}, // 102
{0x8EDF98B59A373FEC, 0x4724BD4189BD5EAD}, // 103
{0xB2977EE300C50FE7, 0x58EDEC91EC2CB658}, // 104
{0xDF3D5E9BC0F653E1, 0x2F2967B66737E3EE}, // 105
{0x8B865B215899F46C, 0xBD79E0D20082EE75}, // 106
{0xAE67F1E9AEC07187, 0xECD8590680A3AA12}, // 107
{0xDA01EE641A708DE9, 0xE80E6F4820CC9496}, // 108
{0x884134FE908658B2, 0x3109058D147FDCDE}, // 109
{0xAA51823E34A7EEDE, 0xBD4B46F0599FD416}, // 110
{0xD4E5E2CDC1D1EA96, 0x6C9E18AC7007C91B}, // 111
{0x850FADC09923329E, 0x03E2CF6BC604DDB1}, // 112
{0xA6539930BF6BFF45, 0x84DB8346B786151D}, // 113
{0xCFE87F7CEF46FF16, 0xE612641865679A64}, // 114
{0x81F14FAE158C5F6E, 0x4FCB7E8F3F60C07F}, // 115
{0xA26DA3999AEF7749, 0xE3BE5E330F38F09E}, // 116
{0xCB090C8001AB551C, 0x5CADF5BFD3072CC6}, // 117
{0xFDCB4FA002162A63, 0x73D9732FC7C8F7F7}, // 118
{0x9E9F11C4014DDA7E, 0x2867E7FDDCDD9AFB}, // 119
{0xC646D63501A1511D, 0xB281E1FD541501B9}, // 120
{0xF7D88BC24209A565, 0x1F225A7CA91A4227}, // 121
{0x9AE757596946075F, 0x3375788DE9B06959}, // 122
{0xC1A12D2FC3978937, 0x0052D6B1641C83AF}, // 123
{0xF209787BB47D6B84, 0xC0678C5DBD23A49B}, // 124
{0x9745EB4D50CE6332, 0xF840B7BA963646E1}, // 125
{0xBD176620A501FBFF, 0xB650E5A93BC3D899}, // 126
{0xEC5D3FA8CE427AFF, 0xA3E51F138AB4CEBF}, // 127
{0x93BA47C980E98CDF, 0xC66F336C36B10138}, // 128
{0xB8A8D9BBE123F017, 0xB80B0047445D4185}, // 129
{0xE6D3102AD96CEC1D, 0xA60DC059157491E6}, // 130
{0x9043EA1AC7E41392, 0x87C89837AD68DB30}, // 131
{0xB454E4A179DD1877, 0x29BABE4598C311FC}, // 132
{0xE16A1DC9D8545E94, 0xF4296DD6FEF3D67B}, // 133
{0x8CE2529E2734BB1D, 0x1899E4A65F58660D}, // 134
{0xB01AE745B101E9E4, 0x5EC05DCFF72E7F90}, // 135
{0xDC21A1171D42645D, 0x76707543F4FA1F74}, // 136
{0x899504AE72497EBA, 0x6A06494A791C53A9}, // 137
{0xABFA45DA0EDBDE69, 0x0487DB9D17636893}, // 138
{0xD6F8D7509292D603, 0x45A9D2845D3C42B7}, // 139
{0x865B86925B9BC5C2, 0x0B8A2392BA45A9B3}, // 140
{0xA7F26836F282B732, 0x8E6CAC7768D7141F}, // 141
{0xD1EF0244AF2364FF, 0x3207D795430CD927}, // 142
{0x8335616AED761F1F, 0x7F44E6BD49E807B9}, // 143
{0xA402B9C5A8D3A6E7, 0x5F16206C9C6209A7}, // 144
{0xCD036837130890A1, 0x36DBA887C37A8C10}, // 145
{0x802221226BE55A64, 0xC2494954DA2C978A}, // 146
{0xA02AA96B06DEB0FD, 0xF2DB9BAA10B7BD6D}, // 147
{0xC83553C5C8965D3D, 0x6F92829494E5ACC8}, // 148
{0xFA42A8B73ABBF48C, 0xCB772339BA1F17FA}, // 149
{0x9C69A97284B578D7, 0xFF2A760414536EFC}, // 150
{0xC38413CF25E2D70D, 0xFEF5138519684ABB}, // 151
{0xF46518C2EF5B8CD1, 0x7EB258665FC25D6A}, // 152
{0x98BF2F79D5993802, 0xEF2F773FFBD97A62}, // 153
{0xBEEEFB584AFF8603, 0xAAFB550FFACFD8FB}, // 154
{0xEEAABA2E5DBF6784, 0x95BA2A53F983CF39}, // 155
{0x952AB45CFA97A0B2, 0xDD945A747BF26184}, // 156
{0xBA756174393D88DF, 0x94F971119AEEF9E5}, // 157
{0xE912B9D1478CEB17, 0x7A37CD5601AAB85E}, // 158
{0x91ABB422CCB812EE, 0xAC62E055C10AB33B}, // 159
{0xB616A12B7FE617AA, 0x577B986B314D600A}, // 160
{0xE39C49765FDF9D94, 0xED5A7E85FDA0B80C}, // 161
{0x8E41ADE9FBEBC27D, 0x14588F13BE847308}, // 162
{0xB1D219647AE6B31C, 0x596EB2D8AE258FC9}, // 163
{0xDE469FBD99A05FE3, 0x6FCA5F8ED9AEF3BC}, // 164
{0x8AEC23D680043BEE, 0x25DE7BB9480D5855}, // 165
{0xADA72CCC20054AE9, 0xAF561AA79A10AE6B}, // 166
{0xD910F7FF28069DA4, 0x1B2BA1518094DA05}, // 167
{0x87AA9AFF79042286, 0x90FB44D2F05D0843}, // 168
{0xA99541BF57452B28, 0x353A1607AC744A54}, // 169
{0xD3FA922F2D1675F2, 0x42889B8997915CE9}, // 170
{0x847C9B5D7C2E09B7, 0x69956135FEBADA12}, // 171
{0xA59BC234DB398C25, 0x43FAB9837E699096}, // 172
{0xCF02B2C21207EF2E, 0x94F967E45E03F4BC}, // 173
{0x8161AFB94B44F57D, 0x1D1BE0EEBAC278F6}, // 174
{0xA1BA1BA79E1632DC, 0x6462D92A69731733}, // 175
{0xCA28A291859BBF93, 0x7D7B8F7503CFDCFF}, // 176
{0xFCB2CB35E702AF78, 0x5CDA735244C3D43F}, // 177
{0x9DEFBF01B061ADAB, 0x3A0888136AFA64A8}, // 178
{0xC56BAEC21C7A1916, 0x088AAA1845B8FDD1}, // 179
{0xF6C69A72A3989F5B, 0x8AAD549E57273D46}, // 180
{0x9A3C2087A63F6399, 0x36AC54E2F678864C}, // 181
{0xC0CB28A98FCF3C7F, 0x84576A1BB416A7DE}, // 182
{0xF0FDF2D3F3C30B9F, 0x656D44A2A11C51D6}, // 183
{0x969EB7C47859E743, 0x9F644AE5A4B1B326}, // 184
{0xBC4665B596706114, 0x873D5D9F0DDE1FEF}, // 185
{0xEB57FF22FC0C7959, 0xA90CB506D155A7EB}, // 186
{0x9316FF75DD87CBD8, 0x09A7F12442D588F3}, // 187
{0xB7DCBF5354E9BECE, 0x0C11ED6D538AEB30}, // 188
{0xE5D3EF282A242E81, 0x8F1668C8A86DA5FB}, // 189
{0x8FA475791A569D10, 0xF96E017D694487BD}, // 190
{0xB38D92D760EC4455, 0x37C981DCC395A9AD}, // 191
{0xE070F78D3927556A, 0x85BBE253F47B1418}, // 192
{0x8C469AB843B89562, 0x93956D7478CCEC8F}, // 193
{0xAF58416654A6BABB, 0x387AC8D1970027B3}, // 194
{0xDB2E51BFE9D0696A, 0x06997B05FCC0319F}, // 195
{0x88FCF317F22241E2, 0x441FECE3BDF81F04}, // 196
{0xAB3C2FDDEEAAD25A, 0xD527E81CAD7626C4}, // 197
{0xD60B3BD56A5586F1, 0x8A71E223D8D3B075}, // 198
{0x85C7056562757456, 0xF6872D5667844E4A}, // 199
{0xA738C6BEBB12D16C, 0xB428F8AC016561DC}, // 200
{0xD106F86E69D785C7, 0xE13336D701BEBA53}, // 201
{0x82A45B450226B39C, 0xECC0024661173474}, // 202
{0xA34D721642B06084, 0x27F002D7F95D0191}, // 203
{0xCC20CE9BD35C78A5, 0x31EC038DF7B441F5}, // 204
{0xFF290242C83396CE, 0x7E67047175A15272}, // 205
{0x9F79A169BD203E41, 0x0F0062C6E984D387}, // 206
{0xC75809C42C684DD1, 0x52C07B78A3E60869}, // 207
{0xF92E0C3537826145, 0xA7709A56CCDF8A83}, // 208
{0x9BBCC7A142B17CCB, 0x88A66076400BB692}, // 209
{0xC2ABF989935DDBFE, 0x6ACFF893D00EA436}, // 210
{0xF356F7EBF83552FE, 0x0583F6B8C4124D44}, // 211
{0x98165AF37B2153DE, 0xC3727A337A8B704B}, // 212
{0xBE1BF1B059E9A8D6, 0x744F18C0592E4C5D}, // 213
{0xEDA2EE1C7064130C, 0x1162DEF06F79DF74}, // 214
{0x9485D4D1C63E8BE7, 0x8ADDCB5645AC2BA9}, // 215
{0xB9A74A0637CE2EE1, 0x6D953E2BD7173693}, // 216
{0xE8111C87C5C1BA99, 0xC8FA8DB6CCDD0438}, // 217
{0x910AB1D4DB9914A0, 0x1D9C9892400A22A3}, // 218
{0xB54D5E4A127F59C8, 0x2503BEB6D00CAB4C}, // 219
{0xE2A0B5DC971F303A, 0x2E44AE64840FD61E}, // 220
{0x8DA471A9DE737E24, 0x5CEAECFED289E5D3}, // 221
{0xB10D8E1456105DAD, 0x7425A83E872C5F48}, // 222
{0xDD50F1996B947518, 0xD12F124E28F7771A}, // 223
{0x8A5296FFE33CC92F, 0x82BD6B70D99AAA70}, // 224
{0xACE73CBFDC0BFB7B, 0x636CC64D1001550C}, // 225
{0xD8210BEFD30EFA5A, 0x3C47F7E05401AA4F}, // 226
{0x8714A775E3E95C78, 0x65ACFAEC34810A72}, // 227
{0xA8D9D1535CE3B396, 0x7F1839A741A14D0E}, // 228
{0xD31045A8341CA07C, 0x1EDE48111209A051}, // 229
{0x83EA2B892091E44D, 0x934AED0AAB460433}, // 230
{0xA4E4B66B68B65D60, 0xF81DA84D56178540}, // 231
{0xCE1DE40642E3F4B9, 0x36251260AB9D668F}, // 232
{0x80D2AE83E9CE78F3, 0xC1D72B7C6B42601A}, // 233
{0xA1075A24E4421730, 0xB24CF65B8612F820}, // 234
{0xC94930AE1D529CFC, 0xDEE033F26797B628}, // 235
{0xFB9B7CD9A4A7443C, 0x169840EF017DA3B2}, // 236
{0x9D412E0806E88AA5, 0x8E1F289560EE864F}, // 237
{0xC491798A08A2AD4E, 0xF1A6F2BAB92A27E3}, // 238
{0xF5B5D7EC8ACB58A2, 0xAE10AF696774B1DC}, // 239
{0x9991A6F3D6BF1765, 0xACCA6DA1E0A8EF2A}, // 240
{0xBFF610B0CC6EDD3F, 0x17FD090A58D32AF4}, // 241
{0xEFF394DCFF8A948E, 0xDDFC4B4CEF07F5B1}, // 242
{0x95F83D0A1FB69CD9, 0x4ABDAF101564F98F}, // 243
{0xBB764C4CA7A4440F, 0x9D6D1AD41ABE37F2}, // 244
{0xEA53DF5FD18D5513, 0x84C86189216DC5EE}, // 245
{0x92746B9BE2F8552C, 0x32FD3CF5B4E49BB5}, // 246
{0xB7118682DBB66A77, 0x3FBC8C33221DC2A2}, // 247
{0xE4D5E82392A40515, 0x0FABAF3FEAA5334B}, // 248
{0x8F05B1163BA6832D, 0x29CB4D87F2A7400F}, // 249
{0xB2C71D5BCA9023F8, 0x743E20E9EF511013}, // 250
{0xDF78E4B2BD342CF6, 0x914DA9246B255417}, // 251
{0x8BAB8EEFB6409C1A, 0x1AD089B6C2F7548F}, // 252
{0xAE9672ABA3D0C320, 0xA184AC2473B529B2}, // 253
{0xDA3C0F568CC4F3E8, 0xC9E5D72D90A2741F}, // 254
{0x8865899617FB1871, 0x7E2FA67C7A658893}, // 255
{0xAA7EEBFB9DF9DE8D, 0xDDBB901B98FEEAB8}, // 256
{0xD51EA6FA85785631, 0x552A74227F3EA566}, // 257
{0x8533285C936B35DE, 0xD53A88958F872760}, // 258
{0xA67FF273B8460356, 0x8A892ABAF368F138}, // 259
{0xD01FEF10A657842C, 0x2D2B7569B0432D86}, // 260
{0x8213F56A67F6B29B, 0x9C3B29620E29FC74}, // 261
{0xA298F2C501F45F42, 0x8349F3BA91B47B90}, // 262
{0xCB3F2F7642717713, 0x241C70A936219A74}, // 263
{0xFE0EFB53D30DD4D7, 0xED238CD383AA0111}, // 264
{0x9EC95D1463E8A506, 0xF4363804324A40AB}, // 265
{0xC67BB4597CE2CE48, 0xB143C6053EDCD0D6}, // 266
{0xF81AA16FDC1B81DA, 0xDD94B7868E94050B}, // 267
{0x9B10A4E5E9913128, 0xCA7CF2B4191C8327}, // 268
{0xC1D4CE1F63F57D72, 0xFD1C2F611F63A3F1}, // 269
{0xF24A01A73CF2DCCF, 0xBC633B39673C8CED}, // 270
{0x976E41088617CA01, 0xD5BE0503E085D814}, // 271
{0xBD49D14AA79DBC82, 0x4B2D8644D8A74E19}, // 272
{0xEC9C459D51852BA2, 0xDDF8E7D60ED1219F}, // 273
{0x93E1AB8252F33B45, 0xCABB90E5C942B504}, // 274
{0xB8DA1662E7B00A17, 0x3D6A751F3B936244}, // 275
{0xE7109BFBA19C0C9D, 0x0CC512670A783AD5}, // 276
{0x906A617D450187E2, 0x27FB2B80668B24C6}, // 277
{0xB484F9DC9641E9DA, 0xB1F9F660802DEDF7}, // 278
{0xE1A63853BBD26451, 0x5E7873F8A0396974}, // 279
{0x8D07E33455637EB2, 0xDB0B487B6423E1E9}, // 280
{0xB049DC016ABC5E5F, 0x91CE1A9A3D2CDA63}, // 281
{0xDC5C5301C56B75F7, 0x7641A140CC7810FC}, // 282
{0x89B9B3E11B6329BA, 0xA9E904C87FCB0A9E}, // 283
{0xAC2820D9623BF429, 0x546345FA9FBDCD45}, // 284
{0xD732290FBACAF133, 0xA97C177947AD4096}, // 285
{0x867F59A9D4BED6C0, 0x49ED8EABCCCC485E}, // 286
{0xA81F301449EE8C70, 0x5C68F256BFFF5A75}, // 287
{0xD226FC195C6A2F8C, 0x73832EEC6FFF3112}, // 288
{0x83585D8FD9C25DB7, 0xC831FD53C5FF7EAC}, // 289
{0xA42E74F3D032F525, 0xBA3E7CA8B77F5E56}, // 290
{0xCD3A1230C43FB26F, 0x28CE1BD2E55F35EC}, // 291
{0x80444B5E7AA7CF85, 0x7980D163CF5B81B4}, // 292
{0xA0555E361951C366, 0xD7E105BCC3326220}, // 293
{0xC86AB5C39FA63440, 0x8DD9472BF3FEFAA8}, // 294
{0xFA856334878FC150, 0xB14F98F6F0FEB952}, // 295
{0x9C935E00D4B9D8D2, 0x6ED1BF9A569F33D4}, // 296
{0xC3B8358109E84F07, 0x0A862F80EC4700C9}, // 297
{0xF4A642E14C6262C8, 0xCD27BB612758C0FB}, // 298
{0x98E7E9CCCFBD7DBD, 0x8038D51CB897789D}, // 299
{0xBF21E44003ACDD2C, 0xE0470A63E6BD56C4}, // 300
{0xEEEA5D5004981478, 0x1858CCFCE06CAC75}, // 301
{0x95527A5202DF0CCB, 0x0F37801E0C43EBC9}, // 302
{0xBAA718E68396CFFD, 0xD30560258F54E6BB}, // 303
{0xE950DF20247C83FD, 0x47C6B82EF32A206A}, // 304
{0x91D28B7416CDD27E, 0x4CDC331D57FA5442}, // 305
{0xB6472E511C81471D, 0xE0133FE4ADF8E953}, // 306
{0xE3D8F9E563A198E5, 0x58180FDDD97723A7}, // 307
{0x8E679C2F5E44FF8F, 0x570F09EAA7EA7649}, // 308
{0xB201833B35D63F73, 0x2CD2CC6551E513DB}, // 309
{0xDE81E40A034BCF4F, 0xF8077F7EA65E58D2}, // 310
{0x8B112E86420F6191, 0xFB04AFAF27FAF783}, // 311
{0xADD57A27D29339F6, 0x79C5DB9AF1F9B564}, // 312
{0xD94AD8B1C7380874, 0x18375281AE7822BD}, // 313
{0x87CEC76F1C830548, 0x8F2293910D0B15B6}, // 314
{0xA9C2794AE3A3C69A, 0xB2EB3875504DDB23}, // 315
{0xD433179D9C8CB841, 0x5FA60692A46151EC}, // 316
{0x849FEEC281D7F328, 0xDBC7C41BA6BCD334}, // 317
{0xA5C7EA73224DEFF3, 0x12B9B522906C0801}, // 318
{0xCF39E50FEAE16BEF, 0xD768226B34870A01}, // 319
{0x81842F29F2CCE375, 0xE6A1158300D46641}, // 320
{0xA1E53AF46F801C53, 0x60495AE3C1097FD1}, // 321
{0xCA5E89B18B602368, 0x385BB19CB14BDFC5}, // 322
{0xFCF62C1DEE382C42, 0x46729E03DD9ED7B6}, // 323
{0x9E19DB92B4E31BA9, 0x6C07A2C26A8346D2}, // 324
};
return g[k - KMIN];
#undef KMIN
#undef KMAX
}
#endif

41
native/test/xassert.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef XASSERT_H
#define XASSERT_H
#ifndef DEBUG
#define xassert(expr) ((void)0)
#else
#include "xprintf.h"
#define xassert(expr) \
((expr) \
? ((void)0) \
: _xassert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__))
static void* raise = 0;
static void xabort() {
*(int*)(raise) = 1;
}
static void _xassert(const char *assertion, const char *file,
const unsigned line, const char *func) {
xprintf("%s:%u: %s Assertion `%s' failed.\n",
file, line, func ? func : "?", assertion);
xabort();
}
#endif // DEBUG
#endif // XASSERT_H

View file

@ -53,6 +53,28 @@ static void printstr(const char *s)
static void printint(int64_t v) static void printint(int64_t v)
{ {
char neg = 0; char neg = 0;
char buf[32] = {};
char *p = &buf[31];
uint64_t u;
if (v < 0) {
u = ~v + 1;
neg = 1;
} else {
u = v;
}
while (u)
{
*--p = (u % 10) + '0';
u /= 10;
}
if (neg) {
*--p = '-';
}
printstr(p);
}
static void printuint(uint64_t v)
{
char buf[32] = {}; char buf[32] = {};
char *p = &buf[31]; char *p = &buf[31];
if (v == 0) if (v == 0)
@ -60,20 +82,11 @@ static void printint(int64_t v)
printch('0'); printch('0');
return; return;
} }
if (v < 0)
{
v = -v;
neg = 1;
}
while (v) while (v)
{ {
*--p = (v % 10) + '0'; *--p = (v % 10) + '0';
v /= 10; v /= 10;
} }
if (neg)
{
*--p = '-';
}
printstr(p); printstr(p);
} }
@ -160,16 +173,26 @@ static void xprintf(const char *fmt, ...)
printch('%'); printch('%');
break; break;
} }
case 's': case 'g':
{ {
printgostr(__builtin_va_arg(va, GoString *)); printgostr(__builtin_va_arg(va, GoString *));
break; break;
} }
case 's':
{
printstr(__builtin_va_arg(va, const char *));
break;
}
case 'd': case 'd':
{ {
printint(__builtin_va_arg(va, int64_t)); printint(__builtin_va_arg(va, int64_t));
break; break;
} }
case 'u':
{
printuint(__builtin_va_arg(va, uint64_t));
break;
}
case 'f': case 'f':
{ {
printint(__builtin_va_arg(va, double)); printint(__builtin_va_arg(va, double));
@ -177,7 +200,7 @@ static void xprintf(const char *fmt, ...)
} }
case 'c': case 'c':
{ {
printch(__builtin_va_arg(va, const char)); printch((char)(__builtin_va_arg(va, int)));
break; break;
} }
case 'x': case 'x':

View file

@ -67,8 +67,6 @@ static inline ssize_t valid_utf8_4byte(uint32_t ubin) {
bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80) bit pattern [11110... 10...... 10...... 10......] (F0 80 80 80)
--------------------------------------------------- ---------------------------------------------------
*/ */
const uint32_t b1_mask = 0x00000080UL;
const uint32_t b1_patt = 0x00000000UL;
const uint32_t b2_mask = 0x0000C0E0UL; const uint32_t b2_mask = 0x0000C0E0UL;
const uint32_t b2_patt = 0x000080C0UL; const uint32_t b2_patt = 0x000080C0UL;
const uint32_t b2_requ = 0x0000001EUL; const uint32_t b2_requ = 0x0000001EUL;
@ -82,10 +80,6 @@ static inline ssize_t valid_utf8_4byte(uint32_t ubin) {
const uint32_t b4_err0 = 0x00000004UL; const uint32_t b4_err0 = 0x00000004UL;
const uint32_t b4_err1 = 0x00003003UL; const uint32_t b4_err1 = 0x00003003UL;
#define is_valid_seq_1(uni) ( \
((uni & b1_mask) == b1_patt) \
)
#define is_valid_seq_2(uni) ( \ #define is_valid_seq_2(uni) ( \
((uni & b2_mask) == b2_patt) && \ ((uni & b2_mask) == b2_patt) && \
((uni & b2_requ)) \ ((uni & b2_requ)) \