Skip to content

Commit

Permalink
fix: int string convert to int64 lose precision #7
Browse files Browse the repository at this point in the history
  • Loading branch information
shockerli committed Sep 3, 2022
1 parent 137f36b commit 38bb361
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 40 deletions.
14 changes: 8 additions & 6 deletions cvte_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ var (
aliasTypeUint0 AliasTypeUint = 0
aliasTypeUint1 AliasTypeUint = 1

aliasTypeString0 AliasTypeString = "0"
aliasTypeString1 AliasTypeString = "1"
aliasTypeString8d15 AliasTypeString = "8.15"
aliasTypeString8d15Minus AliasTypeString = "-8.15"
aliasTypeStringOn AliasTypeString = "on"
aliasTypeStringOff AliasTypeString = "off"
aliasTypeString0 AliasTypeString = "0"
aliasTypeString1 AliasTypeString = "1"
aliasTypeString8d15 AliasTypeString = "8.15"
aliasTypeString8d15Minus AliasTypeString = "-8.15"
aliasTypeStringOn AliasTypeString = "on"
aliasTypeStringOff AliasTypeString = "off"
aliasTypeStringLosePrecisionInt64 AliasTypeString = "7138826985640367621"
aliasTypeStringLosePrecisionFloat64 AliasTypeString = "7138826985640367621.18"

pointerRunes = []rune("中国")
pointerInterNil *AliasTypeInterface
Expand Down
81 changes: 47 additions & 34 deletions int.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"math"
"strconv"
"strings"
)

// Uint64 convert an interface to an uint64 type, with default value
Expand Down Expand Up @@ -318,15 +319,9 @@ func convUint64(val interface{}) (uint64, error) {
}
return 0, nil
case string:
vvv, err := strconv.ParseFloat(vv, 64)
if err == nil && vvv >= 0 && vvv <= math.MaxUint64 {
return uint64(math.Trunc(vvv)), nil
}
return str2uint64(vv)
case []byte:
vvv, err := strconv.ParseFloat(string(vv), 64)
if err == nil && vvv >= 0 && vvv <= math.MaxUint64 {
return uint64(math.Trunc(vvv)), nil
}
return str2uint64(string(vv))
}

// indirect type
Expand All @@ -340,15 +335,9 @@ func convUint64(val interface{}) (uint64, error) {
}
return 0, nil
case string:
vvv, err := strconv.ParseFloat(vv, 64)
if err == nil && vvv >= 0 && vvv <= math.MaxUint64 {
return uint64(math.Trunc(vvv)), nil
}
return str2uint64(vv)
case []byte:
vvv, err := strconv.ParseFloat(string(vv), 64)
if err == nil && vvv >= 0 && vvv <= math.MaxUint64 {
return uint64(math.Trunc(vvv)), nil
}
return str2uint64(string(vv))
case uint, uint8, uint16, uint32, uint64:
return rv.Uint(), nil
case int, int8, int16, int32, int64:
Expand Down Expand Up @@ -409,17 +398,9 @@ func convInt64(val interface{}) (int64, error) {
}
return 0, nil
case string:
vvv, err := strconv.ParseFloat(vv, 64)
if err == nil && vvv <= math.MaxInt64 {
return int64(math.Trunc(vvv)), nil
}
return 0, errConvFail
return str2int64(vv)
case []byte:
vvv, err := strconv.ParseFloat(string(vv), 64)
if err == nil && vvv <= math.MaxInt64 {
return int64(math.Trunc(vvv)), nil
}
return 0, errConvFail
return str2int64(string(vv))
}

// indirect type
Expand All @@ -433,15 +414,9 @@ func convInt64(val interface{}) (int64, error) {
}
return 0, nil
case string:
vvv, err := strconv.ParseFloat(vv, 64)
if err == nil && vvv <= math.MaxInt64 {
return int64(math.Trunc(vvv)), nil
}
return str2int64(vv)
case []byte:
vvv, err := strconv.ParseFloat(string(vv), 64)
if err == nil && vvv <= math.MaxInt64 {
return int64(math.Trunc(vvv)), nil
}
return str2int64(string(vv))
case uint, uint8, uint16, uint32, uint64, uintptr:
if rv.Uint() <= math.MaxInt64 {
return int64(rv.Uint()), nil
Expand All @@ -456,3 +431,41 @@ func convInt64(val interface{}) (int64, error) {

return 0, errConvFail
}

// convert an int or float string to int64
// "12" => 12
// "12.01" => 12
// "-12" => -12
// "-12.01" => -12
func str2int64(s string) (i int64, err error) {
// ensure can be converted to float
_, err = strconv.ParseFloat(s, 64)
if err != nil {
return
}

// trim the decimal part
if i := strings.Index(s, "."); i >= 0 {
s = s[:i]
}
i, err = strconv.ParseInt(s, 10, 64)
return
}

// convert an int or float string to uint64
// "12" => 12
// "12.01" => 12
func str2uint64(s string) (i uint64, err error) {
// ensure can be converted to float
_, err = strconv.ParseFloat(s, 64)
if err != nil {
return
}

// trim the decimal part
if i := strings.Index(s, "."); i >= 0 {
s = s[:i]
}
i, err = strconv.ParseUint(s, 10, 64)
return
}
4 changes: 4 additions & 0 deletions int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,8 @@ func TestUint64E(t *testing.T) {
{&aliasTypeString1, 1, false},
{aliasTypeString8d15, 8, false},
{&aliasTypeString8d15, 8, false},
{aliasTypeStringLosePrecisionInt64, 7138826985640367621, false},
{aliasTypeStringLosePrecisionFloat64, 7138826985640367621, false},
{aliasTypeBool4True, 1, false},
{&aliasTypeBool4True, 1, false},
{aliasTypeBool4False, 0, false},
Expand Down Expand Up @@ -1622,6 +1624,8 @@ func TestInt64E(t *testing.T) {
{&aliasTypeString8d15, 8, false},
{aliasTypeString8d15Minus, -8, false},
{&aliasTypeString8d15Minus, -8, false},
{aliasTypeStringLosePrecisionInt64, 7138826985640367621, false},
{aliasTypeStringLosePrecisionFloat64, 7138826985640367621, false},
{AliasTypeBytes("0"), 0, false},
{AliasTypeBytes("10.98"), 10, false},
{aliasTypeBool4True, 1, false},
Expand Down

0 comments on commit 38bb361

Please sign in to comment.