Better safe integer range for numbers

This commit optimizes the safe float to int conversion function
by using the full -9007199254740991 to 9007199254740991 range as
suggested at:

https://tc39.es/ecma262/#sec-number.min_safe_integer

closes #174
This commit is contained in:
tidwall 2020-11-04 16:26:43 -07:00
parent 2f043b7abd
commit 5100d6926a
1 changed files with 24 additions and 36 deletions

View File

@ -125,16 +125,17 @@ func (t Result) Int() int64 {
return n return n
case Number: case Number:
// try to directly convert the float64 to int64 // try to directly convert the float64 to int64
n, ok := floatToInt(t.Num) i, ok := safeInt(t.Num)
if !ok { if ok {
// now try to parse the raw string return i
n, ok = parseInt(t.Raw)
if !ok {
// fallback to a standard conversion
return int64(t.Num)
}
} }
return n // now try to parse the raw string
i, ok = parseInt(t.Raw)
if ok {
return i
}
// fallback to a standard conversion
return int64(t.Num)
} }
} }
@ -150,16 +151,17 @@ func (t Result) Uint() uint64 {
return n return n
case Number: case Number:
// try to directly convert the float64 to uint64 // try to directly convert the float64 to uint64
n, ok := floatToUint(t.Num) i, ok := safeInt(t.Num)
if !ok { if ok && i >= 0 {
// now try to parse the raw string return uint64(i)
n, ok = parseUint(t.Raw)
if !ok {
// fallback to a standard conversion
return uint64(t.Num)
}
} }
return n // now try to parse the raw string
u, ok := parseUint(t.Raw)
if ok {
return u
}
// fallback to a standard conversion
return uint64(t.Num)
} }
} }
@ -2525,25 +2527,11 @@ func parseInt(s string) (n int64, ok bool) {
return n, true return n, true
} }
const minUint53 = 0 func safeInt(f float64) (n int64, ok bool) {
const maxUint53 = 4503599627370495 if f < -9007199254740991 || f > 9007199254740991 {
const minInt53 = -2251799813685248 return 0, false
const maxInt53 = 2251799813685247
func floatToUint(f float64) (n uint64, ok bool) {
n = uint64(f)
if float64(n) == f && n >= minUint53 && n <= maxUint53 {
return n, true
} }
return 0, false return int64(f), true
}
func floatToInt(f float64) (n int64, ok bool) {
n = int64(f)
if float64(n) == f && n >= minInt53 && n <= maxInt53 {
return n, true
}
return 0, false
} }
// execModifier parses the path to find a matching modifier function. // execModifier parses the path to find a matching modifier function.