Golang - 浮点数转整数的转换

7
我的问题看起来很简单,但我还没有解决它.. 用户输入一个字符串表示的金额 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)

}

1
你无法这样做。那就是浮点数的工作原理。浮点数不是实数,因此无法表示某些十进制数字。你要么必须非常小心地实现正确舍入,或者一直使用分(cents)或使用十进制类型。很快就会变得非常麻烦。祝你好运。 - Volker
1
如果你想了解为什么有些值无法表示,这篇文章很好地解释了浮点数的工作原理:http://fabiensanglard.net/floating_point_visually_explained/ - Peter
1
并且该博文的对应反馈渠道是https://news.ycombinator.com/item?id=15359574 - Scott Stensland
2个回答

13

字符串 到 浮点数 再到 整数

如果你想先将金额转换为浮点数,则在下一步中不要进行转换,而是使用四舍五入

由于转换会保留整数部分,在转换之前加上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 如何将数字四舍五入到最接近的 0.05

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

另一个选项是完全跳过浮点数。为此,我们可以将假定保存浮点数的输入字符串解析为由点号 . 分隔的 2 个整数:"元.分"(其中 都是整数):

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将会导致错误的结果。


4
不要用浮点数表示货币,而应该使用代表分的整数。
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)
}

你应该清理用户输入的数据,因为它们可能会给你 .40 或 4.50 或 $40 ,但这很容易在它还是一个字符串时处理,并可以成为你的转换方法的一部分。在转换之前执行此操作,然后可以将字符串解析为以美分为单位。对于用户输入,你应该有一个 stringToCents 方法和一个 centsToString 方法用于格式化货币,这是边界,其他地方使用美分。
如果你将其解析并存储为美分,则始终需要在需要计算时显式转换为浮点数,然后再转换回美分,你永远不会被浮点数的舍入规则或不准确性所困扰,因为你随后明确说明每个计算将使用哪种舍入方式(在货币方面有很多任意规则,这与浮点数问题无关)。
查看此相关问题的答案以获取更多此类问题的示例。 为什么不使用 Double 或 Float 表示货币?

1
除非以分为单位(或相应货币的单位)输入货币值,否则这将是可怕的用户体验。 - Peter
4
将用户表示法(£23.00、3.43或£3)转换为分值并将分值格式化为货币形式以展示给用户并不太困难。我并不是在主张让用户使用分来操作,只是始终以分作为存储单位。 - Kenny Grant
1
@KennyGrant 基本上这就是提问者想要做的事情:将用户输入(以浮点数给出的美元)转换为整数(以分为单位的数量)。 - icza
4
不是的,你不需要转换为浮点数。 - Kenny Grant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接