IEEE 754 二进制浮点数对于金钱而言不精确

当我使用math.Floor浮点变量时遇到问题(向下舍入/截断精度部分)。我怎样才能正确地做到这一点?


package main


import (

    "fmt"

    "math"

)


func main() {

    var st float64 = 1980

    var salePrice1 = st * 0.1 / 1.1

    fmt.Printf("%T:%v\n", salePrice1, salePrice1) // 179.9999

    var salePrice2 = math.Floor(st * 0.1 / 1.1)

    fmt.Printf("%T:%v\n", salePrice2, salePrice2) // 179

}


游乐场:https://play.golang.org/p/49TjJwwEdEJ


输出:


float64:179.99999999999997

float64:179

我期望 的输出为1980 * 0.1 / 1.1,180但实际输出为179。


凤凰求蛊
浏览 126回答 2
2回答

慕工程0101907

原问题:golang中的楼层数不正确当我将 Math.Floor 与 float 变量一起使用时遇到问题(向下舍入/截断精度部分)。我怎样才能正确地做到这一点?package mainimport (    "fmt"    "math")func main() {    var st float64 = 1980    var salePrice1 = st * 0.1 / 1.1    fmt.Printf("%T:%v\n", salePrice1, salePrice1)    var salePrice2 = math.Floor(st * 0.1 / 1.1)    fmt.Printf("%T:%v\n", salePrice2, salePrice2)}我预计 1980 * 0.1 / 1.1 的产量是 180,但实际产量是 179。”操场:输出:float64:179.99999999999997float64:179XY 问题询问您尝试的解决方案,而不是您的实际问题:XY 问题。显然,这是一个金钱计算salePrice1。货币计算使用精确的十进制计算,而不是不精确的二进制浮点计算。对于货币计算,使用整数。例如,package mainimport "fmt"func main() {    var st int64 = 198000 // $1980.00 as cents    fmt.Printf("%[1]T:%[1]v\n", st)    fmt.Printf("$%d.%02d\n", st/100, st%100)    var n, d int64 = 1, 11    fmt.Printf("%d, %d\n", n, d)    var salePrice1 int64 = (st * n) / d // round down    fmt.Printf("%[1]T:%[1]v\n", salePrice1)    fmt.Printf("$%d.%02d\n", salePrice1/100, salePrice1%100)    var salePrice2 int64 = ((st*n)*10/d + 5) / 10 // round half up    fmt.Printf("%[1]T:%[1]v\n", salePrice2)    fmt.Printf("$%d.%02d\n", salePrice2/100, salePrice2%100)    var salePrice3 int64 = (st*n + (d - 1)) / d // round up    fmt.Printf("%[1]T:%[1]v\n", salePrice1)    fmt.Printf("$%d.%02d\n", salePrice3/100, salePrice3%100)}游乐场:https://play.golang.org/p/HbqVJUXXR-N输出:int64:198000$1980.001, 11int64:18000$180.00int64:18000$180.00int64:18000$180.00

千巷猫影

试试这个:    st := 1980.0    f := 0.1 / 1.1    salePrice1 := st * f    salePrice2 := math.Floor(salePrice1)    fmt.Println(salePrice2) // 180这是一个很大的话题:对于会计系统:答案是浮点错误缓解。(注意:一种缓解技术是使用int64、uint64、 或big.Int)请参阅:每个计算机科学家应该了解的浮点运算 https://en.wikipedia.org/wiki/Double- precision_floating-point_format https://en.wikipedia.org/wiki/IEEE_floating_point让我们从以下开始:fmt.Println(1.0 / 3.0) // 0.3333333333333333IEEE 754 二进制表示:fmt.Printf("%#X\n", math.Float64bits(1.0/3.0)) // 0X3FD55555555555551.1 的 IEEE 754 二进制表示:fmt.Printf("%#X\n", math.Float64bits(1.1))        // 0X3FF199999999999Afmt.Printf("%#X\n", math.Float64bits(st*0.1/1.1)) // 0X40667FFFFFFFFFFF现在,让:st := 1980.0f := 0.1 / 1.1IEEE 754 的二进制表示为f:fmt.Printf("%#X\n", math.Float64bits(f)) // 0X3FB745D1745D1746和:salePrice1 := st * ffmt.Println(salePrice1) // 180fmt.Printf("%#X\n", math.Float64bits(salePrice1)) // 0X4066800000000000salePrice2 := math.Floor(salePrice1)fmt.Printf("%#X\n", math.Float64bits(salePrice2)) // 0X4066800000000000在计算机上使用浮点数与使用笔和纸不同(浮点计算错误):    var st float64 = 1980    var salePrice1 = st * 0.1 / 1.1    fmt.Println(salePrice1) // 179.99999999999997salePrice1是 179.99999999999997 而不是 180.0,因此小于或等于 179.99999999999997 的整数值是 179:请参阅文档func Floor(x float64) float64:Floor 返回小于或等于 x 的最大整数值。看:    fmt.Println(math.Floor(179.999))       // 179    fmt.Println(math.Floor(179.5 + 0.5))   // 180    fmt.Println(math.Floor(179.999 + 0.5)) // 180    fmt.Println(math.Floor(180.0))         // 180
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go