一尘不染

IEEE 754二进制浮点数不精确

go

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.1180的,但实际产量179


阅读 293

收藏
2020-07-02

共1个答案

一尘不染

原始问题:


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

参考文献:

每个计算机科学家都应了解的浮点运算法则
通用十进制算术

2020-07-02