将浮点字符串转换为int

时间:2018-08-02 18:28:18

标签: go

我的服务以字符串形式接收价格,例如“ 12.34”。我必须将其保存为美分(db),因此必须为1234。以下解决方案安全吗?安全意味着结果始终相同且正确。 “ 12.34”必须为1234,但不能为1235或1233。

s := "12.34"
f, _ := strconv.ParseFloat(s, 64)
i := int(100 * f)

(我这里不处理错误,因为问题不在于错误处理)

2 个答案:

答案 0 :(得分:1)

Go使用IEEE-754个二进制浮点数。浮点数不精确。不要将它们用于金融交易。使用整数。

例如,

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 := "12.34"
    fmt.Println(parseCents(s))
    s = "-12.34"
    fmt.Println(parseCents(s))
    s = "12.3"
    fmt.Println(parseCents(s))
}

游乐场:https://play.golang.org/p/AwXg4_jp8lo

输出:

1234 <nil>
-1234 <nil>
0 format error: 12.3

答案 1 :(得分:-2)

如果您可以保证该金额始终以两位数为单位,当然解决方法很简单,只需删除。并解析为整数,就不需要浮点数。

不,这并不安全,请考虑$ 12、12.4 12.00以及四舍五入错误,因为您首先要通过浮点数(浮点数在设计上是不精确的)。我认为最好先将字符串转换为美分(确保它具有。确保在。之后具有两位数字,然后除去数字之外的任何内容),然后转换不必经过浮点运算。

如果这是来自用户输入或您无法控制的其他服务,则应使用意外的输入为此编写一些表测试。像这样:

https://play.golang.org/p/AiikcIMwgZP

var tests = map[string]int64{
    "10":             1000,
    "12.34":          1234,
    "12.3":           1230,
    "€12.3":          1230,
    "$12.99":         1299,
    "123":            12300,
    "12344444444.04": 1234444444404,
    "$12.991":        1299,
    "0.29":           29,
}


func parseCents(s string) (int64, error) {

    // Check it has . if not add 00
    if !strings.Contains(s, ".") {
        s += ".00"
    }

    // Check it has two digits after . if not add 0
    if strings.Index(s, ".") > len(s)-3 {
        s += "0"
    }

    // Remove dot to get cents
    s = strings.Replace(s, ".", "", 1)

    // Remove any stray formatting users might add
    s = strings.Trim(s, "£€$ ")

    // Parse int
    return strconv.ParseInt(s, 10, 64)
}

有关使用浮点数作为货币的更多信息,请参见以下答案(这在所有语言中都是一个问题):

Go - monetary calculations