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