【问题标题】:Golang - float to int conversionGolang - float 到 int 的转换
【发布时间】:2018-03-11 13:03:54
【问题描述】:

我的问题看起来很简单,但我还没有解决它.. 用户输入金额 xx.xx 作为字符串。之后,我将字符串转换为浮点值(一些美元,一些美分),例如,让它成为 655.18 (float64) 然后,我需要将此金额转换为美分 - 655.18*100,结果为 65517.9999999,因此当我将此值转换为 int 时,我得到 65517,因此损失了 1 美分。 如何避免这种行为?

代码:

package main

import (
    "fmt"
    "strconv"
)

func CheckParamsPur(sa string) (amount float64) {
    amount, _ = strconv.ParseFloat(sa, 64)
    return amount
}

func main() {

    fmt.Print("Enter a number: ")
    var input string
    fmt.Scanf("%s", &input)
    amount := int(CheckParamsPur(input) * (100))

    fmt.Println(amount)

}

【问题讨论】:

  • 你不能。这就是花车的工作原理。浮点数不是实数,只是 不能 表示一些十进制数。您要么必须非常小心并实施适当的舍入,要么一直使用美分,要么使用小数类型。这很快就会变得丑陋。祝你好运。
  • 如果您想了解为什么某些值无法表示,这篇文章解释了浮点数如何很好地工作:fabiensanglard.net/floating_point_visually_explained
  • 以及该博文的相应反向渠道news.ycombinator.com/item?id=15359574

标签: variables go type-conversion rounding


【解决方案1】:

string 到浮点数到整数

如果您首先想将金额解析为浮点数,那么在下一步中不要转换,而是使用 四舍五入

由于转换保留整数部分,在转换前添加0.5。因此,如果小数部分小于0.5,则添加0.5 不会增加整数部分,因此转换后整数部分将相同(向下舍入)。如果小数部分大于 0.5,加上 0.5 会增加整数部分,转换后我们得到原始整数部分的高 1(四舍五入)。

在您的情况下,乘以 100 后,在进行转换之前添加 0.5 :

f := 655.17
i := int(f*100 + 0.5)
fmt.Println(i)

输出(在Go Playground 上试试):

65517

阅读涵盖此内容及更多内容的相关问题:Golang Round to Nearest 0.05

将整数和小数部分分别解析为 2 个整数

另一种选择是完全跳过浮点数。为此,我们可以解析输入string,它应该将浮点数保存为两个整数,由一个点分隔."dollars.cents"(其中dollarscents 都是整数):

s := "655.17"

var dollars int64
var cents uint64
if _, err := fmt.Sscanf(s, "%d.%d", &dollars, &cents); err != nil {
    panic(err)
}
if cents > 99 {
    panic("cents cannot be greater than 99")
}

var total int64
if dollars >= 0 {
    total = dollars*100 + int64(cents)
} else {
    total = dollars*100 - int64(cents)
}
fmt.Println(total)

再次输出(在Go Playground上试试):

65517

注意:上述解析代码要求您输入 2 位数的美分,例如655.70,输入 655.7 会产生不好的结果。

【讨论】:

    【解决方案2】:

    不要使用浮点数作为货币。请改用表示美分的整数。

    package main
    
    import (
        "fmt"
        "strconv"
        "strings"
    )
    
    func main() {
        input := "655.18"
        c := strings.Replace(input, ".", "", -1)
        cents, _ := strconv.ParseInt(c, 10, 64)
        fmt.Println(cents)
    }
    

    您可能还应该整理用户输入,因为他们可能会给您 0.40 或 4.50 或 40 美元,但这很容易做到,因为它是一个字符串并且可以成为您转换方法的一部分。在转换之前执行此操作,然后您可以将字符串解析为美分。您应该有一个用于用户输入的 stringToCents 方法和一个用于格式化作为边界的货币的 centsToString 方法,其他任何地方都使用美分。

    如果您解析并存储为美分,您将始终必须在需要计算的地方显式转换为浮点数,然后再返回美分,您永远不会对浮点数的舍入规则或不准确性感到惊讶,因为您随后明确说明了哪个每次计算都将使用舍入(有很多关于货币舍入的任意规则,这变得非常必要。除了浮点数的问题)。

    请参阅此相关问题的答案,了解更多示例,了解这会让您感到困惑。

    Why not use Double or Float to represent currency?

    【讨论】:

    • 除了让用户以美分(或等值货币)输入货币价值的用户体验很糟糕。
    • 将用户表示(23.00 英镑、3.43 或 3 英镑)转换为美分值并格式化美分以显示为货币以向用户展示并不难。我并不是在提倡让用户以美分工作,只是始终以美分存储。
    • @KennyGrant 基本上这就是提问者想要做的:将用户输入(以浮点数形式给出的美元)转换为整数(美分数)。
    • 不,不是,你不必转换成浮点数
    猜你喜欢
    • 2016-09-01
    • 2011-09-28
    • 2021-04-01
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多