2 回答
TA贡献1887条经验 获得超5个赞
原问题:
golang中的楼层数不正确
当我将 Math.Floor 与 float 变量一起使用时遇到问题(向下舍入/截断精度部分)。我怎样才能正确地做到这一点?
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)
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.99999999999997
float64:179
XY 问题询问您尝试的解决方案,而不是您的实际问题:XY 问题。
显然,这是一个金钱计算salePrice1。货币计算使用精确的十进制计算,而不是不精确的二进制浮点计算。
对于货币计算,使用整数。例如,
package main
import "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.00
1, 11
int64:18000
$180.00
int64:18000
$180.00
int64:18000
$180.00
TA贡献1829条经验 获得超7个赞
试试这个:
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.3333333333333333
IEEE 754 二进制表示:
fmt.Printf("%#X\n", math.Float64bits(1.0/3.0)) // 0X3FD5555555555555
1.1 的 IEEE 754 二进制表示:
fmt.Printf("%#X\n", math.Float64bits(1.1)) // 0X3FF199999999999A
fmt.Printf("%#X\n", math.Float64bits(st*0.1/1.1)) // 0X40667FFFFFFFFFFF
现在,让:
st := 1980.0
f := 0.1 / 1.1
IEEE 754 的二进制表示为f:
fmt.Printf("%#X\n", math.Float64bits(f)) // 0X3FB745D1745D1746
和:
salePrice1 := st * f
fmt.Println(salePrice1) // 180
fmt.Printf("%#X\n", math.Float64bits(salePrice1)) // 0X4066800000000000
salePrice2 := 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.99999999999997
salePrice1是 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
- 2 回答
- 0 关注
- 125 浏览
添加回答
举报