I've been working on a project where I have to convert a string to a uint, to make sure some money values are matching:
total, err := strconv.ParseFloat(paymentResp.Transactions[0].Amount.Total, 64)
if err != nil {
return ctx.JSON(http.StatusBadRequest, err.Error())
}
if o.TotalPrice != uint(total*100) {
return ctx.JSON(http.StatusBadRequest, "Unable to verify amount paid")
}
But I've seemingly found a problem when trying to do the strconv.ParseFloat()
on a couple of numbers, then attempting to multiply them by 100 (to get the cents value).
I've created an example here: Go Playground
f, _ := strconv.ParseFloat("79.35", 64)
fmt.Println(uint(f*100)) //7934
f2, _ := strconv.ParseFloat("149.20", 64)
fmt.Println(uint(f2*100)) //14919
Is ParseFloat()
what I should be using in this scenario? If not, I'd love to hear a brief explanation on this, as I'm still a programmer in learning.
Go uses IEEE-754 binary floating-point numbers. Floating-point numbers are imprecise. Don't use them for financial transactions. Use integers.
For example,
package main
import (
"fmt"
"strconv"
"strings"
)
func parseCents(s string) (int64, error) {
n := strings.SplitN(s, ".", 3)
if len(n) != 2 || len(n[1]) != 2 {
err := fmt.Errorf("format error: %s", s)
return 0, err
}
d, err := strconv.ParseInt(n[0], 10, 56)
if err != nil {
return 0, err
}
c, err := strconv.ParseUint(n[1], 10, 8)
if err != nil {
return 0, err
}
if d < 0 {
c = -c
}
return d*100 + int64(c), nil
}
func main() {
s := "79.35"
fmt.Println(parseCents(s))
s = "149.20"
fmt.Println(parseCents(s))
s = "-149.20"
fmt.Println(parseCents(s))
s = "149.2"
fmt.Println(parseCents(s))
}
Playground: https://play.golang.org/p/mGuO51QWyIv
Output:
7935 <nil>
14920 <nil>
-14920 <nil>
0 format error: 149.2
Based on @peterSO's answer, with some bugfix and enhancement:
https://play.golang.org/p/YcRLeEJ7lTA
package main
import (
"fmt"
"strconv"
"strings"
)
func parseCents(s string) (int64, error) {
var ds string
var cs string
n := strings.SplitN(s, ".", 3)
switch len(n) {
case 1:
ds = n[0]
cs = "0"
case 2:
ds = n[0]
switch len(n[1]) {
case 1:
cs = n[1] + "0"
case 2:
cs = n[1]
default:
return 0, fmt.Errorf("invalid format:%s", s)
}
default:
return 0, fmt.Errorf("invalid format:%s", s)
}
d, err := strconv.ParseInt(ds, 10, 0)
if err != nil {
return 0, err
}
c, err := strconv.ParseUint(cs, 10, 0)
if err != nil {
return 0, err
}
cents := d * 100
if strings.HasPrefix(s, "-") {
cents -= int64(c)
} else {
cents += int64(c)
}
return cents, nil
}
func main() {
examples := map[string]int64{
"79.35": 7935,
"149.20": 14920,
"-149.20": -14920,
"149.2": 14920,
"-0.12": -12,
"12": 1200,
"1.234": 0,
"1.2.34": 0,
}
for s, v := range examples {
cents, err := parseCents(s)
fmt.Println(cents, cents == v, err)
}
}
you can split the string, and parse them to an int.
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
a:=strings.Split("75.35",".")
if len(a)>2{
panic("badly formatted price")
}
v,_:=strconv.ParseInt(a[1],10,64)
w,_:=strconv.ParseInt(a[0],10,64)
fmt.Println(uint(w*100+v))
}
its working in this link https://play.golang.org/p/5s_FTAKSo9M
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.