mirror of
https://github.com/ii64/sonic.git
synced 2026-06-23 09:56:44 +08:00
fix: parsing to float64 when the integer(int64) overflow
This commit is contained in:
parent
f9632ab873
commit
e88411dafe
6 changed files with 818 additions and 846 deletions
|
|
@ -34,8 +34,8 @@ type atofTest struct {
|
||||||
// Tests from Go strconv package, https://github.com/golang/go/blob/master/src/strconv/atof_test.go
|
// Tests from Go strconv package, https://github.com/golang/go/blob/master/src/strconv/atof_test.go
|
||||||
// All tests are passed in Go encoding/json.
|
// All tests are passed in Go encoding/json.
|
||||||
var atoftests = []atofTest{
|
var atoftests = []atofTest{
|
||||||
{"1.234e", "1.234", nil},
|
{"1.234e", "", nil}, // error
|
||||||
{"1i", "1", nil},
|
{"1i", "1", nil}, // pass
|
||||||
{"1", "1", nil},
|
{"1", "1", nil},
|
||||||
{"1e23", "1e+23", nil},
|
{"1e23", "1e+23", nil},
|
||||||
{"1E23", "1e+23", nil},
|
{"1E23", "1e+23", nil},
|
||||||
|
|
@ -140,19 +140,25 @@ var atoftests = []atofTest{
|
||||||
{"1090544144181609348671888949248", "1.0905441441816093e+30", nil},
|
{"1090544144181609348671888949248", "1.0905441441816093e+30", nil},
|
||||||
// slightly above, rounds up
|
// slightly above, rounds up
|
||||||
{"1090544144181609348835077142190", "1.0905441441816094e+30", nil},
|
{"1090544144181609348835077142190", "1.0905441441816094e+30", nil},
|
||||||
|
|
||||||
|
// Corner case between int64 and float64 for the input
|
||||||
|
{"9223372036854775807", "9223372036854775807", nil}, // max int64: (1 << 63) - 1
|
||||||
|
{"9223372036854775808", "9223372036854775808", nil},
|
||||||
|
{"-9223372036854775808", "-9223372036854775808", nil}, // min int64: 1 << 63
|
||||||
|
{"-9223372036854775809", "-9223372036854775809", nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecodeFloat(t *testing.T) {
|
func TestDecodeFloat(t *testing.T) {
|
||||||
var sonicout, stdout interface{}
|
for i, tt := range atoftests {
|
||||||
for _, tt := range atoftests {
|
|
||||||
// default float64
|
// default float64
|
||||||
|
var sonicout, stdout interface{}
|
||||||
sonicerr := decoder.NewDecoder(tt.in).Decode(&sonicout)
|
sonicerr := decoder.NewDecoder(tt.in).Decode(&sonicout)
|
||||||
stderr := json.NewDecoder(strings.NewReader(tt.in)).Decode(&stdout)
|
stderr := json.NewDecoder(strings.NewReader(tt.in)).Decode(&stdout)
|
||||||
if !reflect.DeepEqual(sonicout, stdout) {
|
if !reflect.DeepEqual(sonicout, stdout) {
|
||||||
t.Fatalf("Test %#v\ngot:\n %#v\nexp:\n %#v\n", tt.in, sonicout, stdout)
|
t.Fatalf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sonicout, stdout)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(sonicerr == nil, stderr == nil) {
|
if !reflect.DeepEqual(sonicerr == nil, stderr == nil) {
|
||||||
t.Fatalf("Test %#v\ngot:\n %#v\nexp:\n %#v\n", tt.in, sonicerr, stderr)
|
t.Fatalf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sonicerr, stderr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,16 +19,16 @@ var (
|
||||||
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 238
|
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 238
|
||||||
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
||||||
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 4951
|
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 4951
|
||||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16081
|
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15993
|
||||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16116
|
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16028
|
||||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13759
|
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13671
|
||||||
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3731
|
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3731
|
||||||
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5972
|
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5972
|
||||||
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 9426
|
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 9426
|
||||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11985
|
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12001
|
||||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13209
|
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13121
|
||||||
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11032
|
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11032
|
||||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13486
|
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13398
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,16 +19,16 @@ var (
|
||||||
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 366
|
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 366
|
||||||
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
||||||
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5299
|
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5299
|
||||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18501
|
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18413
|
||||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18536
|
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 18448
|
||||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15701
|
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15613
|
||||||
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3979
|
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3979
|
||||||
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 7136
|
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 7136
|
||||||
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11379
|
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11379
|
||||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13927
|
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13943
|
||||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15151
|
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15063
|
||||||
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13090
|
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13090
|
||||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15428
|
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15340
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -412,12 +412,12 @@ void vstring(const GoString *src, long *p, JsonState *ret) {
|
||||||
man_nd++; \
|
man_nd++; \
|
||||||
} else { \
|
} else { \
|
||||||
exp10++; \
|
exp10++; \
|
||||||
} \
|
}
|
||||||
|
|
||||||
#define add_float_to_mantissa(man, man_nd, exp10, dig) \
|
#define add_float_to_mantissa(man, man_nd, exp10, dig) \
|
||||||
man = man * 10 + dig; \
|
man = man * 10 + dig; \
|
||||||
man_nd++; \
|
man_nd++; \
|
||||||
exp10--; \
|
exp10--;
|
||||||
|
|
||||||
#define parse_float_digits(val, sgn, ...) \
|
#define parse_float_digits(val, sgn, ...) \
|
||||||
while (i < n && s[i] >= '0' && s[i] <= '9' __VA_ARGS__) { \
|
while (i < n && s[i] >= '0' && s[i] <= '9' __VA_ARGS__) { \
|
||||||
|
|
@ -490,7 +490,9 @@ static inline int is_atof_exact(uint64_t man, int exp, int sgn, double *val) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
f *= sgn;
|
if (sgn == -1) {
|
||||||
|
f = -f;
|
||||||
|
}
|
||||||
*val = 0;
|
*val = 0;
|
||||||
|
|
||||||
if (exp == 0 || man == 0) {
|
if (exp == 0 || man == 0) {
|
||||||
|
|
@ -563,12 +565,6 @@ void vnumber(const GoString *src, long *p, JsonState *ret) {
|
||||||
check_eof()
|
check_eof()
|
||||||
check_sign(sgn = -1)
|
check_sign(sgn = -1)
|
||||||
|
|
||||||
/* zero */
|
|
||||||
if (i + 1 == n && s[i] == '0') {
|
|
||||||
i++;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for leading zero */
|
/* check for leading zero */
|
||||||
check_digit()
|
check_digit()
|
||||||
check_leading_zero()
|
check_leading_zero()
|
||||||
|
|
@ -634,10 +630,8 @@ void vnumber(const GoString *src, long *p, JsonState *ret) {
|
||||||
exp10 += exp * esm;
|
exp10 += exp * esm;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
if (ret->vt == V_INTEGER) {
|
if (ret->vt == V_INTEGER) {
|
||||||
/* if INT64_MIN <= man * sgn <= INT64_MAX */
|
if ( exp10 == 0 && (man >> 63) == 0) {
|
||||||
if ( exp10 == 0 && (((man & ((uint64_t)1 << 63)) == 0) || ((man & sgn) == man))) {
|
|
||||||
ret->iv = (int64_t)man * sgn;
|
ret->iv = (int64_t)man * sgn;
|
||||||
ret->dv = (double)(ret->iv);
|
ret->dv = (double)(ret->iv);
|
||||||
} else { // integer overflow
|
} else { // integer overflow
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue